Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 3544 → Rev 3545

/kernel/trunk/network/udp.inc
1,153 → 1,325
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; ;;
;; UDP.INC ;;
;; ;;
;; UDP Processes for Menuet OS TCP/IP stack ;;
;; Part of the tcp/ip network stack for KolibriOS ;;
;; ;;
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; See file COPYING for details ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
$Revision: 2995 $
 
 
;*******************************************************************
; Interface
;
; udp_rx Handles received IP packets with the UDP protocol
;
;*******************************************************************
struct UDP_header
 
SourcePort dw ?
DestinationPort dw ?
Length dw ? ; Length of (UDP Header + Data)
Checksum dw ?
 
ends
 
 
align 4
uglobal
UDP_PACKETS_TX rd MAX_NET_DEVICES
UDP_PACKETS_RX rd MAX_NET_DEVICES
endg
 
 
;-----------------------------------------------------------------
;
; UDP Payload ( Data field in IP datagram )
; UDP_init
;
; 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
; This function resets all UDP variables
;
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Source Port | Destination Port |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | Length ( UDP Header + Data ) | Checksum |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; | UDP Data |
; +-+-+-.......... -+
;
;-----------------------------------------------------------------
macro UDP_init {
 
struc UDP_PACKET
{ .SourcePort dw ? ;+00
.DestinationPort dw ? ;+02
.Length dw ? ;+04 - Length of (UDP Header + Data)
.Checksum dw ? ;+06
.Data db ? ;+08
xor eax, eax
mov edi, UDP_PACKETS_TX
mov ecx, 2*MAX_NET_DEVICES
rep stosd
}
 
virtual at 0
UDP_PACKET UDP_PACKET
end virtual
 
macro UDP_checksum IP1, IP2 { ; esi = ptr to udp packet, ecx = packet size, destroys: ecx, edx
 
;***************************************************************************
; Function
; udp_rx [by Johnny_B]
; Pseudoheader
mov edx, IP_PROTO_UDP
 
add dl, [IP1+1]
adc dh, [IP1+0]
adc dl, [IP1+3]
adc dh, [IP1+2]
 
adc dl, [IP2+1]
adc dh, [IP2+0]
adc dl, [IP2+3]
adc dh, [IP2+2]
 
adc dl, cl ; byte[esi+UDP_header.Length+1]
adc dh, ch ; byte[esi+UDP_header.Length+0]
 
; Done with pseudoheader, now do real header
adc dl, byte[esi+UDP_header.SourcePort+1]
adc dh, byte[esi+UDP_header.SourcePort+0]
 
adc dl, byte[esi+UDP_header.DestinationPort+1]
adc dh, byte[esi+UDP_header.DestinationPort+0]
 
adc dl, byte[esi+UDP_header.Length+1]
adc dh, byte[esi+UDP_header.Length+0]
 
adc edx, 0
 
; Done with header, now do data
push esi
movzx ecx, [esi+UDP_header.Length]
rol cx , 8
sub cx , sizeof.UDP_header
add esi, sizeof.UDP_header
 
call checksum_1
call checksum_2
pop esi
 
add [esi+UDP_header.Checksum], dx ; this final instruction will set or clear ZF :)
 
}
 
 
;-----------------------------------------------------------------
;
; Description
; UDP 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
; UDP_input:
;
;***************************************************************************
; Called by IPv4_input,
; this procedure will inject the udp data diagrams in the application sockets.
;
; IN: [esp] = Pointer to buffer
; [esp+4] = size of buffer
; ebx = ptr to device struct
; ecx = UDP Packet size
; esi = ptr to UDP header
; edi = ptr to ipv4 source and dest address
;
; OUT: /
;
;-----------------------------------------------------------------
align 4
UDP_input:
 
proc udp_rx stdcall
push eax
DEBUGF 1,"UDP_input: size=%u\n", ecx
 
; First validate the header & checksum. Discard buffer if error
; First validate, checksum
 
neg [esi + UDP_header.Checksum] ; substract checksum from 0
jz .no_checksum ; if checksum is zero, it is considered valid
 
; otherwise, we will re-calculate the checksum and add it to this value, thus creating 0 when it is correct
 
UDP_checksum (edi), (edi+4)
jnz .checksum_mismatch
 
.no_checksum:
DEBUGF 1,"UDP_input: checksum ok\n"
 
; Convert length to little endian
 
rol [esi + UDP_header.Length], 8
 
; Look for a socket where
; IP Packet UDP Destination Port = local Port
; IP Packet SA = Remote IP
 
mov ax, [edx + 20 + UDP_PACKET.DestinationPort] ; get the local port from
; the IP packet's UDP header
mov cx, [esi + UDP_header.SourcePort]
mov dx, [esi + UDP_header.DestinationPort]
mov edi, [edi + 4] ; ipv4 source address
mov eax, net_sockets
 
mov ebx, net_sockets
 
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .exit ; No match, so exit
cmp [ebx + SOCKET.LocalPort], ax ; ax will hold the 'wrong' value,
; but the comparision is correct
jne .next_socket ; Return back if no match
mov eax, [eax + SOCKET.NextPtr]
or eax, eax
jz .dump
 
; For dhcp, we must allow any remote server to respond.
; I will accept the first incoming response to be the one
; I bind to, if the socket is opened with a destination IP address of
; 255.255.255.255
cmp [ebx + SOCKET.RemoteIP], 0xffffffff
je @f
cmp [eax + SOCKET.Domain], AF_INET4
jne .next_socket
 
mov eax, [edx + IP_PACKET.SourceAddress] ; get the Source address from the IP packet
cmp [ebx + SOCKET.RemoteIP], eax
jne .exit ; Quit if the source IP is not valid
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP
jne .next_socket
 
@@: ; OK - we have a valid UDP packet for this socket.
; First, update the sockets remote port number with the incoming msg
; - it will have changed
; from the original ( 69 normally ) to allow further connects
mov ax, [edx + 20 + UDP_PACKET.SourcePort] ; get the UDP source port
; ( was 69, now new )
mov [ebx + SOCKET.RemotePort], ax
cmp [eax + UDP_SOCKET.LocalPort], dx
jne .next_socket
 
; Now, copy data to socket. We have socket address as [eax + sockets].
; We have IP packet in edx
DEBUGF 1,"UDP_input: socket=%x\n", eax
 
; get # of bytes in ecx
movzx ecx, [edx + IP_PACKET.TotalLength] ; total length of IP packet. Subtract
xchg cl, ch ; 20 + 8 gives data length
sub ecx, 28
;;; TODO: when packet is processed, check more sockets!
 
mov eax, [ebx + SOCKET.rxDataCount] ; get # of bytes already in buffer
add [ebx + SOCKET.rxDataCount], ecx ; increment the count of bytes in buffer
; cmp [eax + IP_SOCKET.RemoteIP], 0xffffffff
; je @f
; cmp [eax + IP_SOCKET.RemoteIP], edi
; jne .next_socket
; @@:
;
; FIXME: UDP should check remote IP, but not under all circumstances!
 
; ecx has count, edx points to data
cmp [eax + UDP_SOCKET.firstpacket], 0
je .updateport
 
add edx, 28 ; edx now points to the data
lea edi, [ebx + eax + SOCKETHEADERSIZE]
mov esi, edx
cmp [eax + UDP_SOCKET.RemotePort], cx
jne .dump
 
cld
rep movsb ; copy the data across
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
popa
 
; flag an event to the application
mov eax, [ebx + SOCKET.PID] ; get socket owner PID
mov ecx, 1
mov esi, TASK_DATA + TASKDATA.pid
.updatesock:
inc [UDP_PACKETS_RX] ; Fixme: correct interface?
 
.next_pid:
cmp [esi], eax
je .found_pid
inc ecx
add esi, 0x20
cmp ecx, [TASK_COUNT]
jbe .next_pid
movzx ecx, [esi + UDP_header.Length]
sub ecx, sizeof.UDP_header
add esi, sizeof.UDP_header
 
jmp .exit
jmp SOCKET_input
 
.found_pid:
shl ecx, 8
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
.updateport:
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
popa
 
.exit:
pop eax
call freeBuff ; Discard the packet
DEBUGF 1,"UDP_input: new remote port=%x\n", cx ; FIXME: find a way to print big endian values with debugf
mov [eax + UDP_SOCKET.RemotePort], cx
inc [eax + UDP_SOCKET.firstpacket]
 
jmp .updatesock
 
 
.checksum_mismatch:
DEBUGF 2,"UDP_input: checksum mismatch\n"
 
.dump:
call kernel_free
add esp, 4 ; pop (balance stack)
DEBUGF 2,"UDP_input: dumping\n"
 
ret
endp
 
 
 
 
;-----------------------------------------------------------------
;
; UDP_output
;
; IN: eax = socket pointer
; ecx = number of bytes to send
; esi = pointer to data
;
;-----------------------------------------------------------------
 
align 4
UDP_output:
 
DEBUGF 1,"UDP_output: socket=%x bytes=%u data_ptr=%x\n", eax, ecx, esi
 
mov dx, [eax + UDP_SOCKET.RemotePort]
DEBUGF 1,"UDP_output: remote port=%x, ", dx ; FIXME: find a way to print big endian values with debugf
rol edx, 16
mov dx, [eax + UDP_SOCKET.LocalPort]
DEBUGF 1,"local port=%x\n", dx
 
sub esp, 8 ; Data ptr and data size will be placed here
push edx esi
mov ebx, [eax + SOCKET.device]
mov edx, [eax + IP_SOCKET.LocalIP]
mov eax, [eax + IP_SOCKET.RemoteIP]
mov di, IP_PROTO_UDP shl 8 + 128
add ecx, sizeof.UDP_header
call IPv4_output
jz .fail
mov [esp + 8], eax ; pointer to buffer start
mov [esp + 8 + 4], edx ; buffer size
 
mov [edi + UDP_header.Length], cx
rol [edi + UDP_header.Length], 8
 
pop esi
push edi ecx
sub ecx, sizeof.UDP_header
add edi, sizeof.UDP_header
shr ecx, 2
rep movsd
mov ecx, [esp]
and ecx, 3
rep movsb
pop ecx edi
 
pop dword [edi + UDP_header.SourcePort]
 
; Checksum
mov esi, edi
mov [edi + UDP_header.Checksum], 0
UDP_checksum (edi-4), (edi-8) ; FIXME: IPv4 packet could have options..
 
DEBUGF 1,"UDP_output: sending with device %x\n", ebx
call [ebx + NET_DEVICE.transmit]
test eax, eax
jnz @f
inc [UDP_PACKETS_TX] ; FIXME: correct device?
@@:
 
ret
 
.fail:
DEBUGF 1,"UDP_output: failed\n"
add esp, 4+4+8
or eax, -1
ret
 
 
 
;---------------------------------------------------------------------------
;
; UDP_API
;
; This function is called by system function 75
;
; IN: subfunction number in bl
; device number in bh
; ecx, edx, .. depends on subfunction
;
; OUT:
;
;---------------------------------------------------------------------------
 
align 4
UDP_api:
 
movzx eax, bh
shl eax, 2
 
test bl, bl
jz .packets_tx ; 0
dec bl
jz .packets_rx ; 1
 
.error:
mov eax, -1
ret
 
.packets_tx:
mov eax, [UDP_PACKETS_TX + eax]
ret
 
.packets_rx:
mov eax, [UDP_PACKETS_RX + eax]
ret
Property changes:
Deleted: svn:keywords
-Rev
\ No newline at end of property