forked from KolibriOS/kolibrios
602924a5b5
fixed bug in netcfg created in last revision netcfg gives error msg when driver is not loaded zeroconfig now works with latest version of libini also fixed use of static and link-local ip in zeroconfig initial IPv4 variables are now 0.0.0.0 instead of 255.255.255.255 created kernel function that shows number of active network devices fixed the use of temp mac variable in IPV4.inc (variable is now in stack) rewrite of ARP code, needs full testing/debugging (new application needed: ARP manager) port numbers are now in INET byte order, as is in posix standards git-svn-id: svn://kolibrios.org@1196 a494cfbc-eb01-0410-851d-a64ba20cac60
963 lines
20 KiB
PHP
963 lines
20 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;; SOCKET.INC ;;
|
|
;; ;;
|
|
;; ;;
|
|
;; Written by hidnplayr@kolibrios.org ;;
|
|
;; based on code by mike.dld ;;
|
|
;; ;;
|
|
;; GNU GENERAL PUBLIC LICENSE ;;
|
|
;; Version 2, June 1991 ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
$Revision: 1019 $
|
|
|
|
align 4
|
|
struct SOCKET
|
|
.PrevPtr dd ? ; pointer to previous socket in list
|
|
.NextPtr dd ? ; pointer to next socket in list
|
|
.Number dd ? ; socket number (unique within single process)
|
|
.PID dd ? ; application process id
|
|
.Domain dd ? ; INET/UNIX/..
|
|
.Type dd ? ; RAW/UDP/TCP/...
|
|
.Protocol dd ? ; ICMP/IPv4/ARP/
|
|
.LocalIP dd ? ; local IP address
|
|
.RemoteIP dd ? ; remote IP address
|
|
.LocalPort dw ? ; local port
|
|
.RemotePort dw ? ; remote port
|
|
.OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state)
|
|
.OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state)
|
|
.rxDataCount dd ? ; rx data count
|
|
.TCBState dd ? ; TCB state
|
|
.TCBTimer dd ? ; TCB timer (seconds)
|
|
.ISS dd ? ; initial send sequence
|
|
.IRS dd ? ; initial receive sequence
|
|
.SND_UNA dd ? ; sequence number of unack'ed sent Packets
|
|
.SND_NXT dd ? ; bext send sequence number to use
|
|
.SND_WND dd ? ; send window
|
|
.RCV_NXT dd ? ; next receive sequence number to use
|
|
.RCV_WND dd ? ; receive window
|
|
.SEG_LEN dd ? ; segment length
|
|
.SEG_WND dd ? ; segment window
|
|
.wndsizeTimer dd ? ; window size timer
|
|
.lock dd ? ; lock mutex
|
|
.backlog dw ? ; Backlog
|
|
.rxData: ; receive data buffer here
|
|
ends
|
|
|
|
MAX_backlog equ 20
|
|
|
|
; socket buffers
|
|
SOCKETBUFFSIZE equ 4096 ; state + config + buffer.
|
|
SOCKETHEADERSIZE equ SOCKET.rxData ; thus 4096 - SOCKETHEADERSIZE bytes data
|
|
|
|
uglobal
|
|
net_sockets rd 2
|
|
last_UDP_port dw ? ; These values give the number of the last used ephemeral port
|
|
last_TCP_port dw ? ;
|
|
endg
|
|
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; SOCKET_init
|
|
;
|
|
; -
|
|
;
|
|
; IN: /
|
|
; OUT: /
|
|
;
|
|
;-----------------------------------------------
|
|
|
|
align 4
|
|
socket_init:
|
|
|
|
mov [net_sockets], 0
|
|
mov [net_sockets + 4], 0
|
|
|
|
mov [last_UDP_port], MIN_EPHEMERAL_PORT
|
|
mov [last_TCP_port], MIN_EPHEMERAL_PORT
|
|
|
|
ret
|
|
|
|
|
|
;-----------------------------------------------------------------------------
|
|
;
|
|
; Socket API (function 74)
|
|
;
|
|
;-----------------------------------------------------------------------------
|
|
|
|
align 4
|
|
sys_socket:
|
|
|
|
test bl, bl
|
|
jz socket_open ; 0
|
|
dec bl
|
|
jz socket_close ; 1
|
|
dec bl
|
|
jz socket_bind ; 2
|
|
dec bl
|
|
jz socket_listen ; 3
|
|
dec bl
|
|
jz socket_connect ; 4
|
|
dec bl
|
|
jz socket_accept ; 5
|
|
dec bl
|
|
jz socket_send ; 6
|
|
dec bl
|
|
jz socket_recv ; 7
|
|
|
|
s_error:
|
|
mov dword [esp+32],-1
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; SOCKET_open
|
|
;
|
|
;
|
|
; IN: domain in ecx
|
|
; type in edx
|
|
; protocol in esi
|
|
; OUT: eax is socket num, -1 on error
|
|
;
|
|
;-----------------------------------------------
|
|
socket_open:
|
|
|
|
DEBUGF 1,"socket_open: domain: %u, type: %u",ecx, edx
|
|
|
|
call net_socket_alloc
|
|
or eax, eax
|
|
jz s_error
|
|
|
|
mov [eax + SOCKET.Domain], ecx
|
|
mov [eax + SOCKET.Type], edx
|
|
mov [eax + SOCKET.Protocol], esi
|
|
|
|
stdcall net_socket_addr_to_num, eax
|
|
DEBUGF 1,", socketnumber: %u\n", eax
|
|
|
|
mov [esp+32], eax
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; SOCKET_bind
|
|
;
|
|
; IN: socket number in ecx
|
|
; pointer to sockaddr struct in edx
|
|
; length of that struct in esi
|
|
; OUT: 0 on success
|
|
;
|
|
;-----------------------------------------------
|
|
|
|
socket_bind:
|
|
|
|
DEBUGF 1,"Socket_bind: socknum: %u sockaddr: %x, length: %u, ",ecx,edx,esi
|
|
|
|
stdcall net_socket_num_to_addr, ecx
|
|
cmp eax, -1
|
|
jz s_error
|
|
|
|
cmp esi, 2
|
|
jl s_error
|
|
|
|
cmp word [edx], AF_INET4
|
|
je .af_inet4
|
|
|
|
jmp s_error
|
|
|
|
.af_inet4:
|
|
|
|
cmp esi, 6
|
|
jl s_error
|
|
|
|
mov bx, word [edx + 2]
|
|
rol bx,8 ;;;
|
|
DEBUGF 1,"local port: %u ",bx
|
|
test bx, bx
|
|
jnz .check_only
|
|
|
|
mov bx , [last_UDP_port]
|
|
|
|
.find_port_loop:
|
|
inc bx
|
|
inc [last_UDP_port]
|
|
|
|
.check_only:
|
|
mov esi, net_sockets
|
|
|
|
.next_udp_socket:
|
|
mov esi, [esi + SOCKET.NextPtr]
|
|
or esi, esi
|
|
jz .udp_port_ok
|
|
|
|
cmp [esi + SOCKET.Type], IP_PROTO_UDP
|
|
jne .next_udp_socket
|
|
|
|
cmp [esi + SOCKET.LocalPort], bx
|
|
jne .next_udp_socket
|
|
|
|
cmp word [edx + 2], 0
|
|
jne s_error
|
|
|
|
cmp bx, MAX_EPHEMERAL_PORT
|
|
jle .find_port_loop
|
|
|
|
mov [last_UDP_port], MIN_EPHEMERAL_PORT
|
|
jmp s_error
|
|
|
|
.udp_port_ok:
|
|
mov word [eax + SOCKET.LocalPort], bx
|
|
|
|
mov ebx, dword [edx + 4]
|
|
mov dword [eax + SOCKET.LocalIP], ebx
|
|
|
|
DEBUGF 1,"local ip: %u.%u.%u.%u\n",\
|
|
[eax + SOCKET.LocalIP]:1,[eax + SOCKET.LocalIP + 1]:1,[eax + SOCKET.LocalIP + 2]:1,[eax + SOCKET.LocalIP + 3]:1
|
|
|
|
mov dword [esp+32],0
|
|
ret
|
|
|
|
|
|
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; SOCKET_connect
|
|
;
|
|
;
|
|
; IN: socket number in ecx
|
|
; pointer to sockaddr struct in edx
|
|
; length of that struct in esi
|
|
; OUT: 0 on success
|
|
;
|
|
;-----------------------------------------------
|
|
align 4
|
|
|
|
socket_connect:
|
|
|
|
DEBUGF 1,"Socket_connect: socknum: %u sockaddr: %x, length: %u,",ecx,edx,esi
|
|
|
|
stdcall net_socket_num_to_addr, ecx
|
|
cmp eax, -1
|
|
jz s_error
|
|
|
|
cmp esi, 2
|
|
jl s_error
|
|
|
|
cmp word [edx], AF_INET4
|
|
je .af_inet4
|
|
|
|
jmp s_error
|
|
|
|
.af_inet4:
|
|
|
|
cmp esi, 8
|
|
jl s_error
|
|
|
|
cmp [eax + SOCKET.Type], IP_PROTO_UDP
|
|
je .udp
|
|
|
|
cmp [eax + SOCKET.Type], IP_PROTO_ICMP
|
|
je .icmp
|
|
|
|
; cmp [eax + SOCKET.Type], IP_PROTO_TCP
|
|
; je .tcp
|
|
|
|
jmp s_error
|
|
|
|
.udp:
|
|
|
|
mov bx , word [edx + 2]
|
|
rol bx, 8
|
|
mov word [eax + SOCKET.RemotePort], bx
|
|
|
|
DEBUGF 1,"remote port: %u ",bx
|
|
|
|
mov ebx, dword [edx + 4]
|
|
mov dword [eax + SOCKET.RemoteIP], ebx
|
|
|
|
DEBUGF 1,"remote ip: %u.%u.%u.%u\n",[edx+4]:1,[edx+5]:1,[edx+6]:1,[edx+7]:1
|
|
|
|
mov dword [esp+32],0
|
|
ret
|
|
|
|
.icmp:
|
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
.tcp:
|
|
|
|
;local sockAddr dd ?
|
|
|
|
; cmp esi, SOCKET_PASSIVE
|
|
; jne .skip_port_check
|
|
;
|
|
; push ebx
|
|
; mov eax, ebx
|
|
; xchg al, ah
|
|
; mov ebx, net_sockets
|
|
;
|
|
; .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:
|
|
|
|
; mov [eax + SOCKET.wndsizeTimer], 0 ; Reset the window timer.
|
|
;
|
|
; xchg bh, bl
|
|
; mov [eax + SOCKET.LocalPort], bx
|
|
; xchg ch, cl
|
|
; mov [eax + SOCKET.RemotePort], cx
|
|
; mov [eax + SOCKET.OrigRemotePort], cx
|
|
; mov ebx, [IP_LIST]
|
|
; mov [eax + SOCKET.LocalIP], ebx
|
|
; mov [eax + SOCKET.RemoteIP], edx
|
|
; mov [eax + SOCKET.OrigRemoteIP], edx
|
|
|
|
; mov ebx, TCB_LISTEN
|
|
; cmp esi, SOCKET_PASSIVE
|
|
; je @f
|
|
; mov ebx, TCB_SYN_SENT
|
|
; @@: mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB
|
|
|
|
; cmp ebx, TCB_LISTEN
|
|
; 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 .exit
|
|
|
|
; push eax
|
|
|
|
; mov bl, TH_SYN
|
|
; xor ecx, ecx
|
|
; stdcall build_tcp_Packet, [sockAddr]
|
|
|
|
; mov eax, NET1OUT_QUEUE
|
|
; mov edx, [IP_LIST]
|
|
; mov ecx, [sockAddr]
|
|
; cmp edx, [ecx + SOCKET.RemoteIP]
|
|
; jne .not_local
|
|
; mov eax, IPIN_QUEUE
|
|
|
|
; .not_local:
|
|
; Send it.
|
|
; pop ebx
|
|
; call queue
|
|
|
|
.exit:
|
|
xor eax, eax
|
|
ret
|
|
|
|
|
|
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; SOCKET_listen
|
|
;
|
|
;
|
|
; IN: socket number in ecx
|
|
; backlog in edx
|
|
; OUT: eax is socket num, -1 on error
|
|
;
|
|
;-----------------------------------------------
|
|
|
|
socket_listen:
|
|
|
|
DEBUGF 1,"Socket_listen: socknum: %u backlog: %u\n",ecx,edx
|
|
|
|
stdcall net_socket_num_to_addr, ecx
|
|
cmp eax, -1
|
|
jz s_error
|
|
|
|
cmp edx, MAX_backlog
|
|
jl .ok
|
|
mov dx , 20
|
|
.ok:
|
|
|
|
mov [eax + SOCKET.backlog], dx
|
|
|
|
; TODO: insert code for active connections like TCP
|
|
|
|
mov dword [esp+32], 0
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; SOCKET_accept
|
|
;
|
|
;
|
|
; IN: socket number in ecx
|
|
; addr in edx
|
|
; addrlen in esi
|
|
; OUT: eax is socket num, -1 on error
|
|
;
|
|
;-----------------------------------------------
|
|
|
|
|
|
socket_accept:
|
|
|
|
DEBUGF 1,"Socket_accept: socknum: %u sockaddr: %x, length: %u\n",ecx,edx,esi
|
|
|
|
stdcall net_socket_num_to_addr, ecx
|
|
or eax, eax
|
|
jz s_error
|
|
mov esi, eax
|
|
|
|
cmp [esi + SOCKET.backlog], 0
|
|
jz s_error
|
|
|
|
call net_socket_alloc
|
|
or eax, eax
|
|
jz s_error
|
|
mov edi, eax
|
|
|
|
dec [esi + SOCKET.backlog]
|
|
|
|
mov ecx, (SOCKET.rxData+3)/4
|
|
rep movsd
|
|
|
|
mov [edi + SOCKET.backlog], 0
|
|
|
|
; TODO: fill in structure in ecx
|
|
|
|
mov [esi + SOCKET.RemoteIP], 0
|
|
mov [esi + SOCKET.RemotePort], 0
|
|
|
|
stdcall net_socket_addr_to_num, eax
|
|
mov [esp+32], eax
|
|
|
|
ret
|
|
|
|
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; SOCKET_close
|
|
;
|
|
;
|
|
; IN: socket number in ecx
|
|
; OUT: eax is socket num, -1 on error
|
|
;
|
|
;-----------------------------------------------
|
|
|
|
socket_close:
|
|
|
|
DEBUGF 1,"Socket_close: socknum: %u\n",ecx
|
|
|
|
stdcall net_socket_num_to_addr, ecx
|
|
or eax, eax
|
|
jz s_error
|
|
|
|
|
|
cmp [eax + SOCKET.Type], IP_PROTO_UDP
|
|
je .udp
|
|
|
|
cmp [eax + SOCKET.Type], IP_PROTO_ICMP
|
|
je .icmp
|
|
|
|
; cmp [eax + SOCKET.Type], IP_PROTO_TCP
|
|
; je .tcp
|
|
|
|
jmp s_error
|
|
|
|
.udp:
|
|
|
|
lea ebx, [eax + SOCKET.lock]
|
|
call wait_mutex
|
|
; TODO: mark the socket for deletion, using the mutex
|
|
|
|
stdcall net_socket_free, eax
|
|
|
|
mov dword [esp+32],0
|
|
ret
|
|
|
|
|
|
.icmp:
|
|
|
|
|
|
|
|
ret
|
|
|
|
.tcp:
|
|
|
|
if 1 = 0
|
|
;local sockAddr dd ?
|
|
|
|
; DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx
|
|
; first, remove any resend entries
|
|
pusha
|
|
|
|
mov esi, resendQ
|
|
mov ecx, 0
|
|
|
|
.next_resendq:
|
|
cmp ecx, NUMRESENDENTRIES
|
|
je .last_resendq ; None left
|
|
cmp [esi + 4], ebx
|
|
je @f ; found one
|
|
inc ecx
|
|
add esi, 8
|
|
jmp .next_resendq
|
|
|
|
@@: mov dword[esi + 4], 0
|
|
inc ecx
|
|
add esi, 8
|
|
jmp .next_resendq
|
|
|
|
.last_resendq:
|
|
popa
|
|
|
|
mov ebx, eax
|
|
; mov [sockAddr], eax
|
|
|
|
cmp [eax + SOCKET.TCBState], TCB_LISTEN
|
|
je .destroy_tcb
|
|
cmp [eax + SOCKET.TCBState], TCB_SYN_SENT
|
|
je .destroy_tcb
|
|
|
|
; Now construct the response, and queue for sending by IP
|
|
mov eax, EMPTY_QUEUE
|
|
call dequeue
|
|
cmp ax, NO_BUFFER
|
|
je .error
|
|
|
|
push eax
|
|
|
|
mov bl, TH_FIN
|
|
xor ecx, ecx
|
|
xor esi, esi
|
|
stdcall build_tcp_Packet, [sockAddr]
|
|
|
|
mov ebx, [sockAddr]
|
|
; increament SND.NXT in socket
|
|
lea esi, [ebx + SOCKET.SND_NXT]
|
|
call inc_inet_esi
|
|
|
|
; Get the socket state
|
|
mov eax, [ebx + SOCKET.TCBState]
|
|
cmp eax, TCB_SYN_RECEIVED
|
|
je .fin_wait_1
|
|
cmp eax, TCB_ESTABLISHED
|
|
je .fin_wait_1
|
|
|
|
; assume CLOSE WAIT
|
|
; Send a fin, then enter last-ack state
|
|
mov [ebx + SOCKET.TCBState], TCB_LAST_ACK
|
|
jmp .send
|
|
|
|
.fin_wait_1:
|
|
; Send a fin, then enter finwait2 state
|
|
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1
|
|
|
|
.send:
|
|
mov eax, NET1OUT_QUEUE
|
|
mov edx, [IP_LIST]
|
|
; mov ecx, [sockAddr]
|
|
cmp edx, [ecx + SOCKET.RemoteIP]
|
|
jne .not_local
|
|
mov eax, IPIN_QUEUE
|
|
|
|
.not_local:
|
|
; Send it.
|
|
pop ebx
|
|
call queue
|
|
jmp .exit
|
|
|
|
|
|
.destroy_tcb:
|
|
|
|
stdcall net_socket_free, eax
|
|
|
|
end if
|
|
|
|
.exit:
|
|
mov dword [esp+32],0
|
|
ret
|
|
|
|
|
|
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; SOCKET_receive
|
|
;
|
|
;
|
|
; IN: socket number in ecx
|
|
; addr in edx
|
|
; addrlen in esi
|
|
; flags in edi
|
|
; OUT: eax is number of bytes copied, -1 on error
|
|
;
|
|
;-----------------------------------------------
|
|
|
|
socket_recv:
|
|
|
|
DEBUGF 1,"Socket_receive: socknum: %u sockaddr: %x, length: %u, flags: %x\n",ecx,edx,esi,edi
|
|
|
|
stdcall net_socket_num_to_addr, ecx ; get real socket address
|
|
or eax, eax
|
|
jz s_error
|
|
|
|
DEBUGF 1,"real socket address:%x\n", eax
|
|
|
|
mov dword[esp+32], -1
|
|
|
|
mov edi, edx
|
|
|
|
lea ebx, [eax + SOCKET.lock]
|
|
call wait_mutex
|
|
|
|
mov ecx, [eax + SOCKET.rxDataCount] ; get count of bytes
|
|
DEBUGF 1,"bytes in socket:%u\n", ecx
|
|
test ecx, ecx ; if count of bytes is zero..
|
|
jz .exit ; exit function (eax will be zero)
|
|
|
|
cmp ecx, esi ; if buffer size is larger then the bytes of data, copy all data
|
|
jle .copy_all_bytes
|
|
|
|
sub ecx, esi ; store new count (data bytes in buffer - bytes we're about to copy)
|
|
mov [eax + SOCKET.rxDataCount], ecx ;
|
|
push ecx
|
|
mov edx, esi
|
|
|
|
call .start_copy ; copy to the application
|
|
|
|
mov dword[esp+32], edx
|
|
|
|
lea edi, [eax + SOCKET.rxData] ; Now shift the remaining bytes to start of buffer
|
|
lea esi, [edi + edx]
|
|
mov ecx, [esp]
|
|
shr ecx, 2 ; divide eax by 4
|
|
rep movsd ; copy all full dwords
|
|
pop ecx
|
|
and ecx, 3
|
|
rep movsb ; copy remaining bytes
|
|
|
|
.exit:
|
|
mov [eax + SOCKET.lock], 0
|
|
ret
|
|
|
|
.copy_all_bytes:
|
|
mov dword[esp+32], ecx
|
|
mov [eax + SOCKET.rxDataCount], 0 ; store new count (zero)
|
|
push dword .exit ; this code results in same as commented out code
|
|
|
|
.start_copy:
|
|
DEBUGF 1,"copying %u bytes\n",ecx
|
|
|
|
lea esi, [eax + SOCKET.rxData]
|
|
push ecx
|
|
shr ecx, 2 ; divide eax by 4
|
|
rep movsd
|
|
pop ecx
|
|
and ecx, 3
|
|
rep movsb ; copy the rest bytes
|
|
|
|
ret ; exit, or go back to shift remaining bytes if any
|
|
|
|
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; SOCKET_send
|
|
;
|
|
;
|
|
; IN: socket number in ecx
|
|
; addr in edx
|
|
; addrlen in esi
|
|
; flags in edi
|
|
; OUT: -1 on error
|
|
;
|
|
;-----------------------------------------------
|
|
|
|
socket_send:
|
|
|
|
DEBUGF 1,"Socket_send: socknum: %u sockaddr: %x, length: %u, flags: %x, ",ecx,edx,esi,edi
|
|
|
|
stdcall net_socket_num_to_addr, ecx ; get real socket address
|
|
or eax, eax
|
|
jz s_error
|
|
|
|
DEBUGF 1,"Socket type:%u\n", [eax + SOCKET.Type]:4
|
|
|
|
cmp [eax + SOCKET.Type], IP_PROTO_UDP
|
|
je .udp
|
|
|
|
cmp [eax + SOCKET.Type], IP_PROTO_ICMP
|
|
je .icmp
|
|
|
|
; cmp [eax + SOCKET.Type], IP_PROTO_TCP
|
|
; je .tcp
|
|
|
|
jmp s_error
|
|
|
|
.udp:
|
|
|
|
DEBUGF 1,"type: UDP\n"
|
|
|
|
mov ecx, esi
|
|
mov esi, edx
|
|
mov edx, dword [eax + SOCKET.LocalPort] ; load local port and remote port at once
|
|
DEBUGF 1,"local port: %u, remote port:%u\n",[eax + SOCKET.LocalPort]:2, [eax + SOCKET.RemotePort]:2
|
|
bswap edx ;;;
|
|
rol edx, 16 ;;;
|
|
mov ebx, [eax + SOCKET.LocalIP]
|
|
mov eax, [eax + SOCKET.RemoteIP]
|
|
|
|
call UDP_create_packet
|
|
|
|
mov [esp+32], eax
|
|
ret
|
|
|
|
.icmp:
|
|
; note: for ICMP sockets the SOCKET.LocalPort is used as the 'Identifier' value for ICMP packets
|
|
; the application must add the header to the data, the kernel will fill in 'identifier' and 'checksum'
|
|
|
|
sub ecx, ICMP_Packet.Data
|
|
mov esi, edx
|
|
push ax
|
|
call IPv4_get_frgmnt_num
|
|
mov dx, ax
|
|
pop ax
|
|
shl edx, 16
|
|
mov dh , [esi + ICMP_Packet.Type]
|
|
mov dl , [esi + ICMP_Packet.Code]
|
|
mov di , [esi + ICMP_Packet.Identifier]
|
|
; mov [eax + SOCKET.LocalPort], di ; Set localport to the identifier number, so we can receive reply's
|
|
shl edi, 16
|
|
mov di , [esi + ICMP_Packet.SequenceNumber]
|
|
add esi, ICMP_Packet.Data
|
|
mov ebx, [eax + SOCKET.LocalIP]
|
|
mov eax, [eax + SOCKET.RemoteIP]
|
|
call ICMP_create_packet
|
|
|
|
mov [esp+32], eax
|
|
ret
|
|
|
|
.tcp:
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Allocate memory for socket data and put new socket into the list
|
|
; Newly created socket is initialized with calling PID and number and
|
|
; put into beginning of list (which is a fastest way).
|
|
;
|
|
; @return socket structure address in EAX
|
|
;
|
|
proc net_socket_alloc stdcall uses ebx ecx edx edi
|
|
stdcall kernel_alloc, SOCKETBUFFSIZE
|
|
DEBUGF 1, "K : net_socket_alloc (0x%x)\n", eax
|
|
; check if we can allocate needed amount of memory
|
|
or eax, eax
|
|
jz .exit
|
|
|
|
; zero-initialize allocated memory
|
|
push eax
|
|
mov edi, eax
|
|
mov ecx, SOCKETBUFFSIZE / 4
|
|
; cld
|
|
xor eax, eax
|
|
rep stosd
|
|
pop eax
|
|
|
|
; add socket to the list by changing pointers
|
|
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
|
|
|
|
@@: ; set socket owner PID to the one of calling process
|
|
mov ebx, [TASK_BASE]
|
|
mov ebx, [ebx + TASKDATA.pid]
|
|
mov [eax + SOCKET.PID], ebx
|
|
|
|
; find first free socket number and use it
|
|
;mov edx, ebx
|
|
mov ebx, net_sockets
|
|
xor ecx, ecx
|
|
.next_socket_number:
|
|
inc ecx
|
|
.next_socket:
|
|
mov ebx, [ebx + SOCKET.NextPtr]
|
|
or ebx, ebx
|
|
jz .last_socket_number
|
|
cmp [ebx + SOCKET.Number], ecx
|
|
jne .next_socket
|
|
;cmp [ebx + SOCKET.PID], edx
|
|
;jne .next_socket
|
|
mov ebx, net_sockets
|
|
jmp .next_socket_number
|
|
|
|
.last_socket_number:
|
|
mov [eax + SOCKET.Number], ecx
|
|
|
|
.exit:
|
|
ret
|
|
endp
|
|
|
|
; Free socket data memory and pop socket off the list
|
|
;
|
|
; @param sockAddr is a socket structure address
|
|
;
|
|
proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD
|
|
mov eax, [sockAddr]
|
|
DEBUGF 1, "K : net_socket_free (0x%x)\n", eax
|
|
; check if we got something similar to socket structure address
|
|
or eax, eax
|
|
jz .error
|
|
|
|
; make sure sockAddr is one of the socket addresses in the list
|
|
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
|
|
|
|
; okay, we found the correct one
|
|
; remove it from the list first, changing pointers
|
|
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
|
|
|
|
@@: ; and finally free the memory structure used
|
|
stdcall kernel_free, [sockAddr]
|
|
ret
|
|
|
|
.error:
|
|
DEBUGF 1, "K : failed\n"
|
|
ret
|
|
endp
|
|
|
|
; Get socket structure address by its number
|
|
; Scan through sockets list to find the socket with specified number.
|
|
; This proc uses SOCKET.PID indirectly to check if socket is owned by
|
|
; calling process.
|
|
;
|
|
; @param sockNum is a socket number
|
|
; @return socket structure address or 0 (not found) in EAX
|
|
;
|
|
proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD
|
|
mov eax, [sockNum]
|
|
; check if we got something similar to socket number
|
|
or eax, eax
|
|
jz .error
|
|
|
|
; scan through sockets list
|
|
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 + SOCKET.Number], eax
|
|
jne .next_socket
|
|
;cmp [ebx + SOCKET.PID], ecx
|
|
;jne .next_socket
|
|
|
|
; okay, we found the correct one
|
|
mov eax, ebx
|
|
ret
|
|
|
|
.error:
|
|
xor eax, eax
|
|
ret
|
|
endp
|
|
|
|
; Get socket number by its structure address
|
|
; Scan through sockets list to find the socket with specified address.
|
|
; This proc uses SOCKET.PID indirectly to check if socket is owned by
|
|
; calling process.
|
|
;
|
|
; @param sockAddr is a socket structure address
|
|
; @return socket number (SOCKET.Number) or 0 (not found) in EAX
|
|
;
|
|
proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD
|
|
mov eax, [sockAddr]
|
|
; check if we got something similar to socket structure address
|
|
or eax, eax
|
|
jz .error
|
|
|
|
; scan through sockets list
|
|
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
|
|
|
|
; okay, we found the correct one
|
|
mov eax, [ebx + SOCKET.Number]
|
|
ret
|
|
|
|
.error:
|
|
xor eax, eax
|
|
ret
|
|
endp
|