0,0 → 1,424 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; UDP.INC ;; |
;; ;; |
;; Part of the tcp/ip network stack for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
$Revision: 2995 $ |
|
|
struct UDP_header |
|
SourcePort dw ? |
DestinationPort dw ? |
Length dw ? ; Length of (UDP Header + Data) |
Checksum dw ? |
|
ends |
|
|
uglobal |
align 4 |
|
UDP_PACKETS_TX rd NET_DEVICES_MAX |
UDP_PACKETS_RX rd NET_DEVICES_MAX |
|
endg |
|
|
;----------------------------------------------------------------- |
; |
; UDP_init |
; |
; This function resets all UDP variables |
; |
;----------------------------------------------------------------- |
macro UDP_init { |
|
xor eax, eax |
mov edi, UDP_PACKETS_TX |
mov ecx, 2*NET_DEVICES_MAX |
rep stosd |
} |
|
|
macro UDP_checksum IP1, IP2 { ; esi = ptr to udp packet, ecx = packet size, destroys: ecx, edx |
|
; 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 :) |
|
} |
|
|
;----------------------------------------------------------------- |
; |
; 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: |
|
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: size=%u\n", ecx |
|
; 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 DEBUG_NETWORK_VERBOSE, "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 |
|
pusha |
mov ecx, socket_mutex |
call mutex_lock |
popa |
|
mov cx, [esi + UDP_header.SourcePort] |
mov dx, [esi + UDP_header.DestinationPort] |
mov edi, [edi + 4] ; ipv4 source address |
mov eax, net_sockets |
|
.next_socket: |
mov eax, [eax + SOCKET.NextPtr] |
or eax, eax |
jz .dump_ |
|
cmp [eax + SOCKET.Domain], AF_INET4 |
jne .next_socket |
|
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
jne .next_socket |
|
cmp [eax + UDP_SOCKET.LocalPort], dx |
jne .next_socket |
|
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: socket=%x\n", eax |
|
pusha |
mov ecx, socket_mutex |
call mutex_unlock |
popa |
|
;;; TODO: when packet is processed, check more sockets! |
|
; 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! |
|
cmp [eax + UDP_SOCKET.RemotePort], 0 |
je .updateport |
|
cmp [eax + UDP_SOCKET.RemotePort], cx |
jne .dump |
|
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
|
.updatesock: |
call NET_ptr_to_num4 |
inc [UDP_PACKETS_RX + edi] |
|
movzx ecx, [esi + UDP_header.Length] |
sub ecx, sizeof.UDP_header |
add esi, sizeof.UDP_header |
|
jmp SOCKET_input |
|
.updateport: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
|
DEBUGF DEBUG_NETWORK_VERBOSE, "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 |
jmp .updatesock |
|
.dump_: |
|
pusha |
mov ecx, socket_mutex |
call mutex_unlock |
popa |
|
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: no socket found\n" |
|
jmp .dump |
|
.checksum_mismatch: |
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: checksum mismatch\n" |
|
.dump: |
call NET_packet_free |
add esp, 4 ; pop (balance stack) |
DEBUGF DEBUG_NETWORK_VERBOSE,"UDP_input: dumping\n" |
|
ret |
|
|
|
|
;----------------------------------------------------------------- |
; |
; UDP_output |
; |
; IN: eax = socket pointer |
; ecx = number of bytes to send |
; esi = pointer to data |
; |
;----------------------------------------------------------------- |
|
align 4 |
UDP_output: |
|
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_output: socket=%x bytes=%u data_ptr=%x\n", eax, ecx, esi |
|
mov dx, [eax + UDP_SOCKET.RemotePort] |
DEBUGF DEBUG_NETWORK_VERBOSE, "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 DEBUG_NETWORK_VERBOSE, "local port=%x\n", dx |
|
sub esp, 8 ; Data ptr and data size will be placed here |
push edx esi |
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 DEBUG_NETWORK_VERBOSE, "UDP_output: sending with device %x\n", ebx |
call [ebx + NET_DEVICE.transmit] |
test eax, eax |
jnz @f |
call NET_ptr_to_num4 |
inc [UDP_PACKETS_TX + edi] |
@@: |
|
ret |
|
.fail: |
DEBUGF DEBUG_NETWORK_ERROR, "UDP_output: failed\n" |
add esp, 4+4+8 |
or eax, -1 |
ret |
|
|
|
|
;----------------------------------------------------------------- |
; |
; UDP_connect |
; |
; IN: eax = socket pointer |
; OUT: eax = 0 ok / -1 error |
; ebx = error code |
; |
;------------------------- |
align 4 |
UDP_connect: |
|
test [eax + SOCKET.state], SS_ISCONNECTED |
jz @f |
call UDP_disconnect |
@@: |
|
push eax edx |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
pop edx eax |
|
; Fill in local IP |
cmp [eax + IP_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST + 4] ; FIXME: use correct local IP |
pop [eax + IP_SOCKET.LocalIP] |
|
; Fill in remote port and IP, overwriting eventually previous values |
pushw [edx + 2] |
pop [eax + UDP_SOCKET.RemotePort] |
|
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
|
; Find a local port, if user didnt define one |
cmp [eax + UDP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
@@: |
|
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue |
pop eax |
|
push eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
pop eax |
|
call SOCKET_is_connected |
|
xor eax, eax |
ret |
|
|
;----------------------------------------------------------------- |
; |
; UDP_disconnect |
; |
; IN: eax = socket pointer |
; OUT: eax = socket pointer |
; |
;------------------------- |
align 4 |
UDP_disconnect: |
|
; TODO: remove the pending received data |
|
call SOCKET_is_disconnected |
|
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 |