forked from KolibriOS/kolibrios
b35a874c08
* pseudoheader for UDP checksum was wrong * network checksum for data with odd length was wrong * stack issues in ARP_add_entry fixed * more correct checking for new packets in pcnet driver git-svn-id: svn://kolibrios.org@1251 a494cfbc-eb01-0410-851d-a64ba20cac60
311 lines
7.5 KiB
PHP
311 lines
7.5 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2009. 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$
|
|
|
|
|
|
struct UDP_Packet
|
|
.SourcePort dw ?
|
|
.DestinationPort dw ?
|
|
.Length dw ? ; Length of (UDP Header + Data)
|
|
.Checksum dw ?
|
|
.Data:
|
|
|
|
ends
|
|
|
|
|
|
align 4
|
|
uglobal
|
|
UDP_PACKETS_TX rd MAX_IP
|
|
UDP_PACKETS_RX rd MAX_IP
|
|
endg
|
|
|
|
|
|
;-----------------------------------------------------------------
|
|
;
|
|
; UDP_init
|
|
;
|
|
; This function resets all UDP variables
|
|
;
|
|
; IN: /
|
|
; OUT: /
|
|
;
|
|
;-----------------------------------------------------------------
|
|
align 4
|
|
UDP_init:
|
|
|
|
xor eax, eax
|
|
mov edi, UDP_PACKETS_TX
|
|
mov ecx, 2*MAX_IP
|
|
rep stosd
|
|
|
|
ret
|
|
|
|
|
|
|
|
;-----------------------------------------------------------------
|
|
;
|
|
; UDP_Handler:
|
|
;
|
|
; Called by IPv4_handler,
|
|
; this procedure will inject the udp data diagrams in the application sockets.
|
|
;
|
|
; IN: Pointer to buffer in [esp]
|
|
; size of buffer in [esp+4]
|
|
; pointer to device struct in ebx
|
|
; UDP Packet size in ecx
|
|
; pointer to UDP Packet data in edx
|
|
; OUT: /
|
|
;
|
|
;-----------------------------------------------------------------
|
|
align 4
|
|
UDP_handler:
|
|
|
|
DEBUGF 1,"UDP_Handler\n"
|
|
; First validate, checksum:
|
|
|
|
DEBUGF 1,"Real UDP checksum: %x\n", [edx + UDP_Packet.Checksum]:4
|
|
mov [edx + UDP_Packet.Checksum], 0
|
|
|
|
pusha
|
|
|
|
rol cx, 8
|
|
push cx
|
|
rol cx, 8
|
|
push word IP_PROTO_UDP shl 8
|
|
push edi
|
|
push esi
|
|
|
|
mov esi, edx
|
|
xor edx, edx
|
|
call checksum_1
|
|
; Checksum for pseudoheader
|
|
mov ecx, 12
|
|
mov esi, esp
|
|
call checksum_1
|
|
add esp, 12
|
|
call checksum_2
|
|
|
|
popa
|
|
|
|
|
|
|
|
; Look for a socket where
|
|
; IP Packet UDP Destination Port = local Port
|
|
; IP Packet SA = Remote IP
|
|
|
|
mov eax, net_sockets
|
|
.try_more:
|
|
mov bx , [edx + UDP_Packet.DestinationPort] ; get the local port from the IP Packet's UDP header
|
|
.next_socket:
|
|
mov eax, [eax + SOCKET_head.NextPtr]
|
|
or eax, eax
|
|
jz .dump
|
|
cmp [eax + SOCKET_head.Domain], AF_INET4
|
|
jne .next_socket
|
|
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
|
|
jne .next_socket
|
|
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
|
|
jne .next_socket
|
|
|
|
DEBUGF 1,"found socket with matching domain, type and localport\n"
|
|
|
|
; 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 [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], 0xffffffff
|
|
je .ok1
|
|
|
|
mov ebx, [esp]
|
|
mov ebx, [ebx + ETH_FRAME.Data + IPv4_Packet.SourceAddress] ; get the Source address from the IP Packet FIXME
|
|
cmp [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], ebx
|
|
jne .try_more ; Quit if the source IP is not valid, check for more sockets with this IP/PORT combination
|
|
|
|
|
|
DEBUGF 1,"Remote Ip matches\n"
|
|
.ok1:
|
|
|
|
mov bx, [edx + UDP_Packet.SourcePort] ; Remote port must be 0, or equal to sourceport of packet
|
|
|
|
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], 0
|
|
je .ok2
|
|
|
|
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx
|
|
jne .dump
|
|
|
|
.ok2:
|
|
|
|
DEBUGF 1,"Found valid UDP packet for socket %x\n", eax
|
|
lea esi, [edx + UDP_Packet.Data]
|
|
movzx ecx, [edx + UDP_Packet.Length]
|
|
rol cx , 8
|
|
sub cx , UDP_Packet.Data
|
|
mov dx , bx
|
|
|
|
|
|
lea ebx, [eax + SOCKET_head.lock]
|
|
call wait_mutex
|
|
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], dx ; update remote port number
|
|
mov [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], edi
|
|
inc [UDP_PACKETS_RX]
|
|
|
|
pop edi
|
|
add esp, 4
|
|
|
|
sub esi, edi
|
|
xchg esi, edi
|
|
jmp socket_internal_receiver
|
|
|
|
|
|
.dump:
|
|
DEBUGF 1,"Dumping UDP packet\n"
|
|
call kernel_free
|
|
add esp, 4 ; pop (balance stack)
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
;-----------------------------------------------------------------
|
|
;
|
|
; UDP_socket_send
|
|
;
|
|
; IN: eax = socket pointer
|
|
; ecx = number of bytes to send
|
|
; esi = pointer to data
|
|
;
|
|
;-----------------------------------------------------------------
|
|
|
|
align 4
|
|
UDP_socket_send:
|
|
|
|
mov edx, dword [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort] ; load local port and remote port at once
|
|
DEBUGF 1,"local port: %x, remote port: %x\n",\
|
|
[eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort]:4,\
|
|
[eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort]:4
|
|
mov ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
|
|
mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
|
|
|
|
DEBUGF 1,"Create UDP Packet (size=%u)\n",ecx
|
|
|
|
mov di , IP_PROTO_UDP
|
|
|
|
sub esp, 8 ; reserve some place in stack for later
|
|
|
|
; Create the pseudoheader in stack,
|
|
; (now that we still have all the variables that are needed.)
|
|
push dword IP_PROTO_UDP shl 8
|
|
|
|
add ecx, UDP_Packet.Data
|
|
|
|
; TODO: fill in: dx = fragment id
|
|
|
|
push edx esi
|
|
call IPv4_create_packet ; TODO: figure out a way to choose between IPv4 and IPv6
|
|
cmp edi, -1
|
|
je .fail
|
|
|
|
mov [esp + 8 + 4], eax ; pointer to buffer start
|
|
mov [esp + 8 + 4 + 4], edx ; buffer size
|
|
|
|
rol cx, 8
|
|
mov [edi + UDP_Packet.Length], cx
|
|
mov [esp + 8 + 2], cx
|
|
ror cx, 8
|
|
|
|
pop esi
|
|
push edi ecx
|
|
sub ecx, UDP_Packet.Data
|
|
add edi, UDP_Packet.Data
|
|
shr ecx, 2
|
|
rep movsd
|
|
mov ecx, [esp]
|
|
and ecx, 3
|
|
rep movsb
|
|
pop ecx edi
|
|
|
|
pop dword [edi + UDP_Packet.SourcePort] ; fill in both portnumbers
|
|
mov [edi + UDP_Packet.Checksum], 0 ; set it to zero, to calculate checksum
|
|
|
|
; Checksum for UDP header + data
|
|
xor edx, edx
|
|
mov esi, edi
|
|
call checksum_1
|
|
; Checksum for pseudoheader
|
|
pushd [edi-4] ; destination address
|
|
pushd [edi-8] ; source address
|
|
mov ecx, 12
|
|
mov esi, esp
|
|
call checksum_1
|
|
add esp, 12 ; remove the pseudoheader from stack
|
|
; Now create the final checksum and store it in UDP header
|
|
call checksum_2
|
|
mov [edi + UDP_Packet.Checksum], dx
|
|
|
|
inc [UDP_PACKETS_TX]
|
|
|
|
DEBUGF 1,"Sending UDP Packet to device %x\n", ebx ;
|
|
jmp ETH_sender ;
|
|
|
|
.fail:
|
|
; todo: queue the packet
|
|
add esp, 8+12+8
|
|
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:
|
|
add eax, UDP_PACKETS_TX
|
|
mov eax, [eax]
|
|
ret
|
|
|
|
.packets_rx:
|
|
add eax, UDP_PACKETS_RX
|
|
mov eax, [eax]
|
|
ret
|