Changes in net branch:

Things changed: sockets data organisation, queue macro's are more universal, new checksum routines, changed socket structures, ...
What's new: UDP checksum generation & validation
Rough TCP code has been written, but not debugged yet.

git-svn-id: svn://kolibrios.org@1249 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2009-11-06 20:45:08 +00:00
parent 725fe0911e
commit 7f9d0c6697
10 changed files with 3390 additions and 3720 deletions

File diff suppressed because it is too large Load Diff

View File

@ -221,7 +221,7 @@ ARP_create_request:
mov ecx, 60 ; minimum packet size mov ecx, 60 ; minimum packet size
mov edx, edi ;;; mov edx, edi ;;;
mov di , ETHER_ARP mov di , ETHER_ARP
call ETH_create_Packet call ETH_create_packet
cmp edi, -1 cmp edi, -1
je .exit je .exit
@ -248,7 +248,7 @@ ARP_create_request:
DEBUGF 1,"ARP Packet for device %x created successfully\n", ebx DEBUGF 1,"ARP Packet for device %x created successfully\n", ebx
push edx ecx push edx ecx
jmp ETH_Sender jmp ETH_sender
.exit: .exit:
add esp, 8 add esp, 8
@ -555,7 +555,7 @@ ARP_handler:
DEBUGF 1,"ARP_Handler - Sending reply \n" DEBUGF 1,"ARP_Handler - Sending reply \n"
jmp ETH_Sender ; And send it! jmp ETH_sender ; And send it!
.exit: .exit:
call kernel_free call kernel_free

View File

@ -3,7 +3,7 @@
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;; ;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;; ;; Distributed under terms of the GNU General Public License ;;
;; ;; ;; ;;
;; IP.INC ;; ;; IPv4.INC ;;
;; ;; ;; ;;
;; Part of the tcp/ip network stack for KolibriOS ;; ;; Part of the tcp/ip network stack for KolibriOS ;;
;; ;; ;; ;;
@ -52,7 +52,7 @@ struct FRAGMENT_entry ; This structure will replace the ethernet header
.PrevPtr dd ? ; Pointer to previous fragment entry (-1 for first packet) .PrevPtr dd ? ; Pointer to previous fragment entry (-1 for first packet)
.NextPtr dd ? ; Pointer to next fragment entry (-1 for last packet) .NextPtr dd ? ; Pointer to next fragment entry (-1 for last packet)
.Owner dd ? ; Pointer to structure of driver .Owner dd ? ; Pointer to structure of driver
rb 2 ; to match ethernet header size rb 2 ; to match ethernet header size ; TODO: fix this hack
.Data: ; Ip header begins here (we will need the IP header to re-construct the complete packet) .Data: ; Ip header begins here (we will need the IP header to re-construct the complete packet)
ends ends
@ -99,10 +99,9 @@ IPv4_init:
;----------------------------------------------------------------- ;-----------------------------------------------------------------
; ;
; IP_Handler: ; IPv4_Handler:
; ;
; Called by eth_handler, ; Will check if IP Packet isnt damaged
; will check if IP Packet isnt damaged
; and call appropriate handler. (TCP/UDP/ICMP/..) ; and call appropriate handler. (TCP/UDP/ICMP/..)
; ;
; It will also re-construct fragmented packets ; It will also re-construct fragmented packets
@ -119,20 +118,27 @@ align 4
IPv4_handler: IPv4_handler:
DEBUGF 1,"IP_Handler - start\n" DEBUGF 1,"IP_Handler - start\n"
mov cx , [edx + IPv4_Packet.HeaderChecksum]
xchg ch , cl ; Get the checksum in intel format
mov word [edx + IPv4_Packet.HeaderChecksum], 0 ; Clear checksum field to recalculating checksum push edx ebx
movzx eax, byte [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field ; save checksum, and clear it in original packet
and eax, 0x0000000F ; mov di , [edx + IPv4_Packet.HeaderChecksum]
shl eax, 2 ; DEBUGF 1,"checksum: %x\n",di
mov word [edx + IPv4_Packet.HeaderChecksum], 0
push edx ; Re-calculate checksum
stdcall checksum_jb, edx, eax ; buf_ptr, buf_size movzx ecx, byte [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field
pop edx and ecx, 0x0000000F ;
cmp cx , ax shl cx , 2 ;
jnz .dump ; if CHECKSUM isn't valid then dump Packet mov esi, edx
xor edx, edx
call checksum_1
call checksum_2
; now compare the two..
cmp dx, di
pop ebx edx
jne .dump ; if checksum isn't valid then dump packet
mov eax, [edx + IPv4_Packet.DestinationAddress] mov eax, [edx + IPv4_Packet.DestinationAddress]
mov edi, BROADCAST mov edi, BROADCAST
@ -183,10 +189,14 @@ IPv4_handler:
add eax, edx add eax, edx
push eax push eax
mov al , [edx + IPv4_Packet.Protocol] mov al , [edx + IPv4_Packet.Protocol]
;----------------------- experimental
mov esi, [edx + IPv4_Packet.SourceAddress]
mov edi, [edx + IPv4_Packet.DestinationAddress]
;-----------------------
pop edx ; Offset to data (tcp/udp/icmp/.. Packet) pop edx ; Offset to data (tcp/udp/icmp/.. Packet)
cmp al , IP_PROTO_TCP cmp al , IP_PROTO_TCP
; je TCP_handler je TCP_handler
cmp al , IP_PROTO_UDP cmp al , IP_PROTO_UDP
je UDP_handler je UDP_handler
@ -385,14 +395,21 @@ IPv4_handler:
movzx eax, byte [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field movzx eax, byte [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field
and ax, 0x000F ; and ax, 0x000F ;
shl ax, 2 ; shl ax, 2 ;
sub ecx, eax ;
sub ecx, eax
add eax, edx add eax, edx
push eax push eax
mov al , [edx + IPv4_Packet.Protocol] mov al , [edx + IPv4_Packet.Protocol]
;----------------------- experimental
mov esi, [edx + IPv4_Packet.SourceAddress]
mov edi, [edx + IPv4_Packet.DestinationAddress]
;-----------------------
pop edx ; Offset to data (tcp/udp/icmp/.. Packet) pop edx ; Offset to data (tcp/udp/icmp/.. Packet)
cmp al , IP_PROTO_TCP cmp al , IP_PROTO_TCP
; je TCP_handler je TCP_handler
cmp al , IP_PROTO_UDP cmp al , IP_PROTO_UDP
je UDP_handler je UDP_handler
@ -493,12 +510,12 @@ IPv4_decrease_fragment_ttls:
; dx = fragment id ; dx = fragment id
; di = protocol ; di = protocol
; ;
; OUT: eax points to buffer start ; OUT: eax = pointer to buffer start
; ebx is size of complete buffer ; ebx = pointer to device struct (needed for sending procedure)
; edi = pointer to start of data (-1 on error)
; ecx = unchanged (packet size of embedded data) ; ecx = unchanged (packet size of embedded data)
; edx = pointer to device struct (needed for sending procedure) ; edx = size of complete buffer
; esi = pointer to sending procedure ; esi = pointer to sending procedure
; edi = pointer to start of data (-1 on error)
; ;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
@ -550,7 +567,7 @@ IPv4_create_packet:
mov ecx, [esp+18] ;; 18 or 22 ?? mov ecx, [esp+18] ;; 18 or 22 ??
add ecx, IPv4_Packet.DataOrOptional add ecx, IPv4_Packet.DataOrOptional
mov di , ETHER_IPv4 mov di , ETHER_IPv4
call ETH_create_Packet ; TODO: figure out a way to make this work with other protocols too call ETH_create_packet ; TODO: figure out a way to make this work with other protocols too
add esp, 6 add esp, 6
cmp edi, -1 cmp edi, -1
je .exit je .exit
@ -571,21 +588,25 @@ IPv4_create_packet:
pop ecx pop ecx
mov [edi + IPv4_Packet.DestinationAddress], ecx mov [edi + IPv4_Packet.DestinationAddress], ecx
push eax push eax ebx edx
stdcall checksum_jb, edi, IPv4_Packet.DataOrOptional ; buf_ptr, buf_size ; calculate checksum
xchg al, ah xor edx, edx
mov [edi + IPv4_Packet.HeaderChecksum], ax mov esi, edi
pop eax ecx mov ecx, IPv4_Packet.DataOrOptional
call checksum_1
call checksum_2
mov [edi + IPv4_Packet.HeaderChecksum], dx
pop edx ebx eax ecx
add edi, IPv4_Packet.DataOrOptional add edi, IPv4_Packet.DataOrOptional
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", edx DEBUGF 1,"IPv4 Packet for device %x created successfully\n", ebx
ret ret
.not_found: .not_found:
DEBUGF 1,"Create IPv4 Packet - ARP entry not found!\n" DEBUGF 1,"Create IPv4 Packet - ARP entry not found!\n"
; TODO: QUEUE! ; TODO: QUEUE the packet to resend later!
.exit: .exit:
add esp, 16 add esp, 16
.exit_: .exit_:

View File

@ -80,13 +80,8 @@ ETH_init:
mov ecx, (1+MAX_ETH_DEVICES) mov ecx, (1+MAX_ETH_DEVICES)
rep stosd rep stosd
mov dword [ETH_IN_QUEUE], ETH_QUEUE_SIZE init_queue ETH_IN_QUEUE
mov dword [ETH_IN_QUEUE+4], ETH_IN_QUEUE + queue.data init_queue ETH_OUT_QUEUE
mov dword [ETH_IN_QUEUE+8], ETH_IN_QUEUE + queue.data
mov dword [ETH_OUT_QUEUE], ETH_QUEUE_SIZE
mov dword [ETH_OUT_QUEUE+4], ETH_OUT_QUEUE + queue.data
mov dword [ETH_OUT_QUEUE+8], ETH_OUT_QUEUE + queue.data
ret ret
@ -104,7 +99,7 @@ ETH_init:
;--------------------------------------------------------- ;---------------------------------------------------------
align 4 align 4
ETH_Add_Device: ETH_add_device:
DEBUGF 1,"ETH_Add_Device: %x ", ebx DEBUGF 1,"ETH_Add_Device: %x ", ebx
@ -122,7 +117,6 @@ ETH_Add_Device:
mov ecx, MAX_ETH_DEVICES ; We need to check whole list because a device may be removed without re-organizing list mov ecx, MAX_ETH_DEVICES ; We need to check whole list because a device may be removed without re-organizing list
mov edi, ETH_DRV_LIST mov edi, ETH_DRV_LIST
cld
repne scasd ; See if device is already in the list repne scasd ; See if device is already in the list
jz .error jz .error
@ -167,7 +161,7 @@ ETH_Add_Device:
;-------------------------------- ;--------------------------------
align 4 align 4
ETH_Remove_Device: ETH_remove_device:
cmp [ETH_RUNNING], 0 cmp [ETH_RUNNING], 0
je .error je .error
@ -212,12 +206,21 @@ ETH_Remove_Device:
;------------------------------------------------------------- ;-------------------------------------------------------------
align 4 align 4
ETH_Receiver: ETH_receiver:
DEBUGF 1,"ETH_Receiver \n" DEBUGF 1,"ETH_Receiver: "
add_to_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, .gohome push ebx
mov esi, esp
add_to_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.size, .fail
DEBUGF 1,"Queued packet successfully\n"
add esp, 4*3
ret
.gohome: .fail:
DEBUGF 1,"ETH_IN_QUEUE is full!\n"
add esp, 4
call kernel_free
add esp, 4
ret ret
@ -238,7 +241,18 @@ ETH_Receiver:
align 4 align 4
ETH_handler: ETH_handler:
get_from_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, .gohome get_from_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.size, .gohome
push ETH_handler
lodsd
mov ebx, eax
lodsd
mov ecx, eax
lodsd
xchg eax, ecx
push ecx
push eax
DEBUGF 1,"ETH_Handler - size: %u\n", ecx DEBUGF 1,"ETH_Handler - size: %u\n", ecx
cmp ecx, 60 ; check packet length cmp ecx, 60 ; check packet length
@ -262,13 +276,13 @@ ETH_handler:
add esp, 4 add esp, 4
.gohome: .gohome:
ret ; return 1. to get more from queue / 2. to caller ret ; return to get more from queue / to caller
;----------------------------------------------------------------- ;-----------------------------------------------------------------
; ;
; ETH_Sender: ; ETH_sender:
; ;
; This function sends an ethernet packet to the correct driver. ; This function sends an ethernet packet to the correct driver.
; ;
@ -280,35 +294,66 @@ ETH_handler:
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 align 4
ETH_Sender: ETH_sender:
DEBUGF 1,"ETH_Sender \n" DEBUGF 1,"ETH_Sender: queuing for device: %x, %u bytes\n", [esp], [esp + 4]
add_to_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, .gohome push ebx
mov esi, esp
.gohome: add_to_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.size, .fail
DEBUGF 1,"Queued packet successfully\n"
add esp, 3*4
ret ret
.fail:
DEBUGF 1,"ETH_OUT_QUEUE is full!\n"
add esp, 4
call kernel_free
add esp, 4
ret
;-----------------------------------------------------------------
;
; ETH_send_queued:
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
align 4 align 4
ETH_send_queued: ETH_send_queued:
get_from_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, .gohome get_from_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.size, .gohome
call ETH_struc2dev ; convert struct ptr to device num (this way we know if driver is still mounted) push ETH_send_queued
lodsd
mov ebx, eax
sub esp, 8
mov edi, esp
movsd
movsd
DEBUGF 1,"dequeued packet for device %x\n", ebx
call ETH_struc2dev ; convert struct ptr to device num (this way we know if driver is still mounted)
cmp edi, -1 cmp edi, -1
je .fail je .fail
DEBUGF 1,"ETH_Sender - device: %u\n", edi jmp [ebx+ETH_DEVICE.transmit] ; we will return to get_from_queue macro after transmitting packet
jmp [ebx+ETH_DEVICE.transmit]
.fail: .fail:
call kernel_free call kernel_free
add esp, 4 ; pop (balance stack) add esp, 4 ; pop (balance stack)
DEBUGF 1,"ETH_Sender - fail\n" DEBUGF 1,"ETH_Sender - fail\n"
.gohome: .gohome:
ret ret
;--------------------------------------------------------------------------- ;---------------------------------------------------------------------------
; ;
; ETH_struc2dev ; ETH_struc2dev
@ -362,7 +407,7 @@ ETH_struc2dev:
;--------------------------------------------------------------------------- ;---------------------------------------------------------------------------
align 4 align 4
ETH_create_Packet: ETH_create_packet:
DEBUGF 1,"Creating Ethernet Packet (size=%u): \n", ecx DEBUGF 1,"Creating Ethernet Packet (size=%u): \n", ecx
@ -394,7 +439,7 @@ ETH_create_Packet:
lea eax, [edi - ETH_FRAME.Data] ; Set eax to buffer start lea eax, [edi - ETH_FRAME.Data] ; Set eax to buffer start
mov edx, ecx ; Set ebx to complete buffer size mov edx, ecx ; Set ebx to complete buffer size
pop ecx pop ecx
mov esi, ETH_Sender mov esi, ETH_sender
xor ebx, ebx ;;;; TODO: Fixme xor ebx, ebx ;;;; TODO: Fixme
mov ebx, [ETH_DRV_LIST + ebx] mov ebx, [ETH_DRV_LIST + ebx]

View File

@ -133,8 +133,8 @@ ICMP_init:
; ;
; ICMP_Handler: ; ICMP_Handler:
; ;
; Called by IP_handler, ; this procedure will send reply's to ICMP echo's
; this procedure will send reply's to ICMP echo's etc ;;; TODO: update this to work with fragmented packets too! ; and insert packets into sockets when needed ;;; TODO: update this to work with fragmented packets too!
; ;
; IN: Pointer to buffer in [esp] ; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4] ; size of buffer in [esp+4]
@ -181,33 +181,31 @@ ICMP_handler: ;TODO: works only on pure ethernet right now !
mov dword [esi + ETH_FRAME.Data + IPv4_Packet.SourceAddress], ecx mov dword [esi + ETH_FRAME.Data + IPv4_Packet.SourceAddress], ecx
; Recalculate ip header checksum ; Recalculate ip header checksum
; mov esi, [esp]
add esi, ETH_FRAME.Data ; Point esi to start of IP Packet add esi, ETH_FRAME.Data ; Point esi to start of IP Packet
movzx eax, byte [esi + IPv4_Packet.VersionAndIHL] ; Calculate IP Header length by using IHL field movzx ecx, byte [esi + IPv4_Packet.VersionAndIHL] ; Calculate IP Header length by using IHL field
and eax, 0x0000000F ; and ecx, 0x0000000F ;
shl eax, 2 ; shl cx , 2
push ebx edx esi push ebx edx ecx esi
stdcall checksum_jb, esi, eax ; calculate the checksum xor edx, edx
pop esi edx ebx call checksum_1
xchg al, ah ; convert to intel byte order call checksum_2
; mov esi, [esp] pop esi
mov word [esi + IPv4_Packet.HeaderChecksum], ax ; Store it in the IP Packet header mov word [esi + IPv4_Packet.HeaderChecksum], dx ; Store it in the IP Packet header
; Recalculate ICMP CheckSum ; Recalculate ICMP CheckSum
; mov esi, [esp] ; Find length of IP Packet movzx eax, word[esi + IPv4_Packet.TotalLength] ; Find length of IP Packet
movzx eax, word[esi + IPv4_Packet.TotalLength] ;
xchg ah , al ; xchg ah , al ;
movzx edi, byte [esi + IPv4_Packet.VersionAndIHL] ; Calculate IP Header length by using IHL field sub eax, [esp] ; Now we know the length of ICMP data in eax
and edi, 0x0000000F ; mov ecx, eax
shl edi, 2 ; mov esi, [esp + 4]
sub ax , di ; Now we know the length of ICMP data in eax xor edx, edx
push ebx edx call checksum_1
stdcall checksum_jb,edx,eax ; Calculate the checksum of icmp data call checksum_2
pop edx ebx mov ax , dx
xchg al, ah ; Convert to intel byte order pop ecx edx ebx
mov word [edx + ICMP_Packet.Checksum], ax mov word [edx + ICMP_Packet.Checksum], ax
jmp ETH_Sender ; Send the reply jmp ETH_sender ; Send the reply
@ -222,20 +220,14 @@ ICMP_handler: ;TODO: works only on pure ethernet right now !
.try_more: .try_more:
mov ax , [edx + ICMP_Packet.Identifier] mov ax , [edx + ICMP_Packet.Identifier]
.next_socket: .next_socket:
mov esi, [esi + SOCKET.NextPtr] mov esi, [esi + SOCKET_head.NextPtr]
or esi, esi or esi, esi
jz .dump jz .dump
cmp [esi + SOCKET.Type], IP_PROTO_ICMP cmp [esi + SOCKET_head.Type], IP_PROTO_ICMP
jne .next_socket jne .next_socket
cmp [esi + SOCKET.LocalPort], ax cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + ICMP_SOCKET.Identifier], ax
jne .next_socket jne .next_socket
cmp [esi + SOCKET.rxDataCount],0 ; get # of bytes already in buffer
jnz .dump ; only one packet at a time may be in the buffer!
cmp ecx, SOCKETBUFFSIZE - SOCKETHEADERSIZE; TODO: fix this problem !
jg .dump
call IPv4_dest_to_dev call IPv4_dest_to_dev
cmp edi,-1 cmp edi,-1
je .dump je .dump
@ -243,60 +235,25 @@ ICMP_handler: ;TODO: works only on pure ethernet right now !
DEBUGF 1,"Found valid ICMP packet for socket %x\n", esi DEBUGF 1,"Found valid ICMP packet for socket %x\n", esi
lea ebx, [esi + SOCKET.lock] lea ebx, [esi + SOCKET_head.lock]
call wait_mutex call wait_mutex
; Now, copy data to socket. We have socket address in esi. ; Now, assign data to socket. We have socket address in esi.
; We have ICMP Packet in edx ; We have ICMP Packet in edx
; number of bytes in ecx ; number of bytes in ecx
; note: we do not strip the header! mov eax, esi
DEBUGF 1,"bytes: %u\n", ecx
mov [esi + SOCKET.rxDataCount], ecx
lea edi, [esi + SOCKETHEADERSIZE]
push esi
push ecx
mov esi, edx
shr ecx, 2
rep movsd ; copy the data across
pop ecx
and ecx, 3
rep movsb
pop esi pop esi
add esp, 4
DEBUGF 1,"ICMP socket updated\n" sub edx, esi
mov edi, edx
mov [esi + SOCKET.lock], 0 jmp socket_internal_receiver
; flag an event to the application
mov eax, [esi + SOCKET.PID] ; get socket owner PID
mov ecx, 1
mov esi, TASK_DATA + TASKDATA.pid
.next_pid:
cmp [esi], eax
je .found_pid
inc ecx
add esi, 0x20
cmp ecx, [TASK_COUNT]
jbe .next_pid
jmp .dump
.found_pid:
shl ecx, 8
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
mov [check_idle_semaphore], 200
.dump: .dump:
DEBUGF 1,"ICMP_Handler - dumping\n" DEBUGF 1,"ICMP_Handler - dumping\n"
call kernel_free call kernel_free
add esp, 8 ; pop (balance stack) add esp, 4 ; pop (balance stack)
ret ret
@ -351,7 +308,7 @@ ICMP_handler_fragments: ; works only on pure ethernet right now !
DEBUGF 1,"ICMP_Handler_fragments - end\n" DEBUGF 1,"ICMP_Handler_fragments - end\n"
call kernel_free call kernel_free
add esp, 8 ; pop (balance stack) add esp, 4 ; pop (balance stack)
ret ret
;----------------------------------------------------------------- ;-----------------------------------------------------------------
@ -397,11 +354,14 @@ ICMP_create_packet:
mov [edi + ICMP_Packet.Identifier], ax mov [edi + ICMP_Packet.Identifier], ax
mov [edi + ICMP_Packet.Checksum], 0 mov [edi + ICMP_Packet.Checksum], 0
stdcall checksum_jb, edi , ecx push eax ebx ecx edx
xchg al, ah mov esi, edi
mov [edi + ICMP_Packet.Checksum], ax xor edx, edx
call checksum_1
call checksum_2
mov [edi + ICMP_Packet.Checksum], dx
pop edx ecx ebx eax esi
pop esi
sub ecx, ICMP_Packet.Data sub ecx, ICMP_Packet.Data
add edi, ICMP_Packet.Data add edi, ICMP_Packet.Data
push cx push cx

View File

@ -15,88 +15,97 @@
$Revision$ $Revision$
struct queue struct queue
.size dd ? .size dd ? ; number of queued packets in thsi queue
.w_ptr dd ? .w_ptr dd ? ; current writing pointer in queue
.r_ptr dd ? .r_ptr dd ? ; current reading pointer
.data: .data:
ends ends
struct queue_entry struct eth_queue_entry
.owner dd ? .owner dd ?
.data_ptr dd ? .data_ptr dd ?
.data_size dd ? .data_size dd ?
.size: .size:
ends ends
struct tcp_in_queue_entry
.data_ptr dd ?
.data_size dd ?
.offset dd ?
.size:
ends
macro add_to_queue ptr, size, returnaddr { struct tcp_out_queue_entry
.data_ptr dd ?
.data_size dd ?
.ttl dd ?
.retries dd ?
.owner dd ?
.sendproc dd ?
.ack_num dd ?
.size:
ends
cmp dword [ptr + queue.size], size ; Check if queue isnt full struct socket_queue_entry
jge .fail .data_ptr dd ?
.data_size dd ?
.offset dd ?
.size:
ends
DEBUGF 1,"Queuing packet for device %x\n",ebx macro add_to_queue ptr, size, entry_size, failaddr {
inc dword [ptr + queue.size] cmp [ptr + queue.size], size ; Check if queue isnt full
jge failaddr
mov edi, dword [ptr + queue.w_ptr] ; Current write pointer (FIFO!) inc [ptr + queue.size]
mov eax, ebx mov edi, [ptr + queue.w_ptr] ; Current write pointer (FIFO!)
stosd mov ecx, entry_size/4 ; Write the queue entry
pop eax rep movsd ;
stosd
pop eax
stosd
cmp edi, size*queue_entry.size+ptr+queue.data ; entry size lea ecx, [size*entry_size+ptr+queue.data]
cmp edi, ecx ; entry size
jl .no_wrap jl .no_wrap
sub edi, size*queue_entry.size sub edi, size*entry_size
.no_wrap: .no_wrap:
mov dword [ptr + queue.w_ptr], edi mov [ptr + queue.w_ptr], edi
jmp returnaddr
.fail:
DEBUGF 1,"queuing failed\n"
call kernel_free
add esp, 4
ret
} }
macro get_from_queue ptr, size, returnaddr {
.start_of_code: macro get_from_queue ptr, size, entry_size, failaddr {
cmp dword [ptr + queue.size], 0 ; any packets queued?
je returnaddr
DEBUGF 1,"Dequeuing packet" cmp [ptr + queue.size], 0 ; any packets queued?
je failaddr
dec dword [ptr + queue.size] dec [ptr + queue.size]
push dword .start_of_code ; return address for call's
mov esi, [ptr + queue.r_ptr] mov esi, [ptr + queue.r_ptr]
lodsd push esi
mov ebx, eax
lodsd
mov ecx, eax
lodsd
push eax
push ecx
xchg eax, ecx
DEBUGF 1," for device %x\n", ebx add esi, entry_size
cmp esi, size*queue_entry.size+ptr+queue.data ; entry size lea ecx, [size*entry_size+ptr+queue.data]
cmp esi, ecx ; entry size
jl .no_wrap jl .no_wrap
sub esi, size*queue_entry.size sub esi, size*entry_size
.no_wrap: .no_wrap:
mov dword [ptr + queue.r_ptr], esi mov dword [ptr + queue.r_ptr], esi
pop esi
} }
macro init_queue queue_ptr {
mov [queue_ptr + queue.size] , 0
lea esi, [queue_ptr + queue.data]
mov [queue_ptr + queue.w_ptr], esi
mov [queue_ptr + queue.r_ptr], esi
}

View File

@ -5,7 +5,6 @@
;; ;; ;; ;;
;; SOCKET.INC ;; ;; SOCKET.INC ;;
;; ;; ;; ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;; ;; Written by hidnplayr@kolibrios.org ;;
;; based on code by mike.dld ;; ;; based on code by mike.dld ;;
;; ;; ;; ;;
@ -16,8 +15,7 @@
$Revision$ $Revision$
align 4 struct SOCKET_head
struct SOCKET
.PrevPtr dd ? ; pointer to previous socket in list .PrevPtr dd ? ; pointer to previous socket in list
.NextPtr dd ? ; pointer to next socket in list .NextPtr dd ? ; pointer to next socket in list
.Number dd ? ; socket number (unique within single process) .Number dd ? ; socket number (unique within single process)
@ -25,35 +23,73 @@ struct SOCKET
.Domain dd ? ; INET/UNIX/.. .Domain dd ? ; INET/UNIX/..
.Type dd ? ; RAW/UDP/TCP/... .Type dd ? ; RAW/UDP/TCP/...
.Protocol dd ? ; ICMP/IPv4/ARP/ .Protocol dd ? ; ICMP/IPv4/ARP/
.LocalIP dd ? ; local IP address .lock dd ? ; lock mutex
.RemoteIP dd ? ; remote IP address .end:
.LocalPort dw ? ; local port (In INET byte order) ends
.RemotePort dw ? ; remote port (IN INET byte order
struct IPv4_SOCKET
.LocalIP dd ?
.RemoteIP dd ?
.SequenceNumber dd ?
; todo: add options (for func 8 and 9)
.end:
ends
struct TCP_SOCKET
.LocalPort dw ? ; In INET byte order
.RemotePort dw ? ; In INET byte order
.backlog dw ? ; Backlog
.OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state) .OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state)
.OrigRemotePort dw ? ; original remote port (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 .TCBState dd ? ; TCB state
.TCBTimer dd ? ; TCB timer (seconds) .TCBTimer dd ? ; TCB timer (seconds)
.ISS dd ? ; initial send sequence .ISS dd ? ; initial send sequence
.IRS dd ? ; initial receive sequence .IRS dd ? ; initial receive sequence
.SND_UNA dd ? ; sequence number of unack'ed sent Packets .SND_UNA dd ? ; sequence number of unack'ed sent Packets
.SND_NXT dd ? ; bext send sequence number to use .SND_NXT dd ? ; next send sequence number to use
.SND_WND dd ? ; send window .SND_WND dd ? ; send window
.RCV_NXT dd ? ; next receive sequence number to use .RCV_NXT dd ? ; next receive sequence number to use
.RCV_WND dd ? ; receive window .RCV_WND dd ? ; receive window
.SEG_LEN dd ? ; segment length .SEG_LEN dd ? ; segment length
.SEG_WND dd ? ; segment window .SEG_WND dd ? ; segment window
.wndsizeTimer dd ? ; window size timer .wndsizeTimer dd ? ; window size timer
.lock dd ? ; lock mutex
.backlog dw ? ; Backlog .flags db ? ; packet flags
.rxData: ; receive data buffer here
.end:
ends ends
MAX_backlog equ 20 struct UDP_SOCKET
; socket buffers .LocalPort dw ? ; In INET byte order
SOCKETBUFFSIZE equ 4096 ; state + config + buffer. .RemotePort dw ? ; In INET byte order
SOCKETHEADERSIZE equ SOCKET.rxData ; thus 4096 - SOCKETHEADERSIZE bytes data
.end:
ends
struct ICMP_SOCKET
.Identifier dw ? ;
.end:
ends
struct IPC_SOCKET
.ConnectedTo dd ? ; Socket number of other socket this one is connected to
.end:
ends
MAX_backlog equ 20 ; backlog for stream sockets
SOCKETBUFFSIZE equ 4096 ; in bytes
SOCKET_QUEUE_SIZE equ 10 ; maximum number ofincoming packets queued for 1 socket
uglobal uglobal
net_sockets rd 2 net_sockets rd 2
@ -110,6 +146,10 @@ sys_socket:
jz socket_send ; 6 jz socket_send ; 6
dec bl dec bl
jz socket_recv ; 7 jz socket_recv ; 7
dec bl
; jz socket_get_opt ; 8
dec bl
; jz socket_set_opt ; 9
s_error: s_error:
mov dword [esp+32],-1 mov dword [esp+32],-1
@ -139,9 +179,9 @@ socket_open:
or eax, eax or eax, eax
jz s_error jz s_error
mov [eax + SOCKET.Domain], ecx mov [eax + SOCKET_head.Domain], ecx
mov [eax + SOCKET.Type], edx mov [eax + SOCKET_head.Type], edx
mov [eax + SOCKET.Protocol], esi mov [eax + SOCKET_head.Protocol], esi
stdcall net_socket_addr_to_num, eax stdcall net_socket_addr_to_num, eax
DEBUGF 1,", socketnumber: %u\n", eax DEBUGF 1,", socketnumber: %u\n", eax
@ -153,6 +193,10 @@ socket_open:
;----------------------------------------------- ;-----------------------------------------------
; ;
; SOCKET_bind ; SOCKET_bind
@ -176,14 +220,28 @@ socket_bind:
jl s_error jl s_error
cmp word [edx], AF_INET4 cmp word [edx], AF_INET4
jne s_error je .af_inet4
cmp word [edx], AF_UNIX
je .af_unix
jmp s_error
.af_unix:
; TODO: write code here
mov dword [esp+32],0
ret
.af_inet4: .af_inet4:
cmp esi, 6 cmp esi, 6
jl s_error jl s_error
mov ecx, [eax + SOCKET.Type] mov ecx, [eax + SOCKET_head.Type]
mov bx, word [edx + 2] mov bx, word [edx + 2]
DEBUGF 1,"local port: %x ",bx DEBUGF 1,"local port: %x ",bx
test bx, bx test bx, bx
@ -194,21 +252,22 @@ socket_bind:
je s_error je s_error
jmp .got_port jmp .got_port
.find_free: .find_free:
call socket_find_port call socket_find_port
test bx, bx test bx, bx
je s_error je s_error
.got_port: .got_port:
DEBUGF 1,"using port: %x ",bx DEBUGF 1,"using port: %x ",bx
mov word [eax + SOCKET.LocalPort], bx mov word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
mov ebx, dword [edx + 4] mov ebx, dword [edx + 4]
mov dword [eax + SOCKET.LocalIP], ebx mov dword [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP], ebx
DEBUGF 1,"local ip: %u.%u.%u.%u\n",\ 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 [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 0]:1,[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 1]:1,\
[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 2]:1,[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 3]:1
mov dword [esp+32],0 mov dword [esp+32],0
ret ret
@ -249,32 +308,33 @@ socket_connect:
cmp esi, 8 cmp esi, 8
jl s_error jl s_error
cmp [eax + SOCKET.Type], IP_PROTO_UDP cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
je .udp je .udp
cmp [eax + SOCKET.Type], IP_PROTO_ICMP cmp [eax + SOCKET_head.Type], IP_PROTO_ICMP
je .icmp je .icmp
cmp [eax + SOCKET.Type], IP_PROTO_TCP cmp [eax + SOCKET_head.Type], IP_PROTO_TCP
je .tcp je .tcp
jmp s_error jmp s_error
.udp: .udp:
mov bx , word [edx + 2] mov bx , word [edx + 2]
mov word [eax + SOCKET.RemotePort], bx mov word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx
DEBUGF 1,"remote port: %x ",bx DEBUGF 1,"remote port: %x ",bx
mov ebx, dword [edx + 4] mov ebx, dword [edx + 4]
mov dword [eax + SOCKET.RemoteIP], ebx mov dword [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], ebx
DEBUGF 1,"remote ip: %u.%u.%u.%u\n",[edx+4]:1,[edx+5]:1,[edx+6]:1,[edx+7]:1 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 mov dword [esp+32],0
ret ret
.icmp: .icmp:
; TODO: write code here
ret ret
@ -387,7 +447,7 @@ socket_listen:
mov dx , 20 mov dx , 20
.ok: .ok:
mov [eax + SOCKET.backlog], dx mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], dx
; TODO: insert code for active connections like TCP ; TODO: insert code for active connections like TCP
@ -420,7 +480,21 @@ socket_accept:
jz s_error jz s_error
mov esi, eax mov esi, eax
cmp [esi + SOCKET.backlog], 0 cmp word [esi + SOCKET_head.Domain], AF_INET4
je .af_inet4
jmp s_error
.af_inet4:
cmp [esi + SOCKET_head.Type], IP_PROTO_TCP
je .tcp
jmp s_error
.tcp:
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], 0
jz s_error jz s_error
call net_socket_alloc call net_socket_alloc
@ -428,19 +502,21 @@ socket_accept:
jz s_error jz s_error
mov edi, eax mov edi, eax
dec [esi + SOCKET.backlog] dec [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog]
mov ecx, (SOCKET.rxData+3)/4 mov ecx, (SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end+3)/4
push esi edi
rep movsd rep movsd
pop edi esi
mov [edi + SOCKET.backlog], 0 mov [edi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], 0
; TODO: fill in structure in ecx ; TODO: fill in structure in ecx
mov [esi + SOCKET.RemoteIP], 0 mov [esi + SOCKET_head.end + IPv4_SOCKET.RemoteIP], 0
mov [esi + SOCKET.RemotePort], 0 mov [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], 0
stdcall net_socket_addr_to_num, eax stdcall net_socket_addr_to_num, edi
mov [esp+32], eax mov [esp+32], eax
ret ret
@ -465,26 +541,23 @@ socket_close:
or eax, eax or eax, eax
jz s_error jz s_error
cmp [eax + SOCKET_head.Domain], AF_INET4
jne s_error
cmp [eax + SOCKET.Type], IP_PROTO_UDP cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
je .udp je .udp
cmp [eax + SOCKET.Type], IP_PROTO_ICMP cmp [eax + SOCKET_head.Type], IP_PROTO_ICMP
je .icmp je .icmp
cmp [eax + SOCKET.Type], IP_PROTO_TCP cmp [eax + SOCKET_head.Type], IP_PROTO_TCP
je .tcp je .tcp
jmp s_error jmp s_error
.udp: .udp:
lea ebx, [eax + SOCKET.lock]
call wait_mutex
; TODO: mark the socket for deletion, using the mutex
stdcall net_socket_free, eax stdcall net_socket_free, eax
mov dword [esp+32],0 mov dword [esp+32],0
ret ret
@ -600,8 +673,8 @@ end if
; ;
; ;
; IN: socket number in ecx ; IN: socket number in ecx
; addr in edx ; addr to buffer in edx
; addrlen in esi ; length of buffer in esi
; flags in edi ; flags in edi
; OUT: eax is number of bytes copied, -1 on error ; OUT: eax is number of bytes copied, -1 on error
; ;
@ -609,70 +682,46 @@ end if
align 4 align 4
socket_recv: socket_recv:
DEBUGF 1,"Socket_receive: socknum: %u sockaddr: %x, length: %u, flags: %x\n",ecx,edx,esi,edi DEBUGF 1,"Socket_receive: socknum: %u bufferaddress: %x, length: %u, flags: %x\n",ecx,edx,esi,edi
stdcall net_socket_num_to_addr, ecx ; get real socket address stdcall net_socket_num_to_addr, ecx ; get real socket address
or eax, eax or eax, eax
jz s_error jz s_error
DEBUGF 1,"real socket address:%x\n", eax DEBUGF 1,"Socket pointer: %x\n", eax
mov dword[esp+32], -1 get_from_queue (eax + 2048), SOCKET_QUEUE_SIZE, 4*3, s_error
mov edi, edx mov edi, edx
mov ecx, [esi + socket_queue_entry.data_size]
lea ebx, [eax + SOCKET.lock] DEBUGF 1,"Got %u bytes of data\n", ecx
call wait_mutex
mov ecx, [eax + SOCKET.rxDataCount] ; get count of bytes cmp ecx, edx
DEBUGF 1,"bytes in socket:%u\n", ecx jle .large_enough
test ecx, ecx ; if count of bytes is zero.. DEBUGF 1,"Buffer too small...\n"
jz .exit ; exit function (eax will be zero) jmp s_error
.large_enough:
cmp ecx, esi ; if buffer size is larger then the bytes of data, copy all data push [esi + socket_queue_entry.data_ptr]
jle .copy_all_bytes mov esi, [esi + socket_queue_entry.offset]
add esi, [esp]
DEBUGF 1,"Source buffer: %x, real addr: %x\n", [esp], esi
sub ecx, esi ; store new count (data bytes in buffer - bytes we're about to copy) mov dword[esp+32+4], ecx ; return number of bytes copied
mov [eax + SOCKET.rxDataCount], ecx ;
push ecx
mov edx, esi
call .start_copy ; copy to the application shr ecx, 1
jnc .nb
movsb
.nb: shr ecx, 1
jnc .nw
movsw
.nw: rep movsd
mov dword[esp+32], edx call kernel_free
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 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
;----------------------------------------------- ;-----------------------------------------------
; ;
@ -695,84 +744,97 @@ socket_send:
or eax, eax or eax, eax
jz s_error jz s_error
cmp word [eax + SOCKET.Domain], AF_INET4 cmp word [eax + SOCKET_head.Domain], AF_INET4
je .af_inet4 je .af_inet4
jmp s_error jmp s_error
;---------
.af_inet4: .af_inet4:
DEBUGF 1,"Socket type:%u\n", [eax + SOCKET_head.Type]:4
DEBUGF 1,"Socket type:%u\n", [eax + SOCKET.Type]:4 cmp [eax + SOCKET_head.Type], IP_PROTO_TCP
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 je .tcp
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
je .udp
cmp [eax + SOCKET_head.Type], SOCK_RAW
je .raw
jmp s_error jmp s_error
;--------
.udp: .udp:
DEBUGF 1,"type: UDP, " DEBUGF 1,"type: UDP, "
cmp [eax + SOCKET.LocalPort],0 cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort],0
jne .port_ok jne @f
push esi push esi
mov ecx, [eax + SOCKET.Type] mov ecx, [eax + SOCKET_head.Type]
call socket_find_port call socket_find_port
test bx, bx test bx, bx
pop esi pop esi
je s_error je s_error
mov [eax + SOCKET.LocalPort], bx mov [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
.port_ok: @@:
mov ecx, esi mov ecx, esi
mov esi, edx mov esi, edx
mov edx, dword [eax + SOCKET.LocalPort] ; load local port and remote port at once
DEBUGF 1,"local port: %x, remote port: %x\n",[eax + SOCKET.LocalPort]:4, [eax + SOCKET.RemotePort]:4
mov ebx, [eax + SOCKET.LocalIP]
mov eax, [eax + SOCKET.RemoteIP]
call UDP_create_packet call UDP_socket_send
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 mov [esp+32], eax
ret ret
.tcp: .tcp:
mov [esp+32], eax
ret ret
;--------
.raw:
cmp [eax + SOCKET_head.Protocol], IP_PROTO_IP
je .raw_ip
cmp [eax + SOCKET_head.Protocol], IP_PROTO_ICMP
je .raw_icmp
jmp s_error
;--------
.raw_ip:
mov [esp+32], eax
ret
.raw_icmp:
; 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
@ -812,15 +874,15 @@ socket_find_port:
mov esi, net_sockets mov esi, net_sockets
.next_socket: .next_socket:
mov esi, [esi + SOCKET.NextPtr] mov esi, [esi + SOCKET_head.NextPtr]
or esi, esi or esi, esi
jz .port_ok jz .port_ok
cmp [esi + SOCKET.Type], ecx cmp [esi + SOCKET_head.Type], ecx
jne .next_socket jne .next_socket
rol bx, 8 rol bx, 8
cmp [esi + SOCKET.LocalPort], bx cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
rol bx, 8 ; this doesnt change the zero flag, does it ? rol bx, 8 ; this doesnt change the zero flag, does it ?
jne .next_socket jne .next_socket
@ -852,14 +914,14 @@ socket_check_port:
mov esi, net_sockets mov esi, net_sockets
.next_socket: .next_socket:
mov esi, [esi + SOCKET.NextPtr] mov esi, [esi + SOCKET_head.NextPtr]
or esi, esi or esi, esi
jz .port_ok jz .port_ok
cmp [esi + SOCKET.Type], ecx cmp [esi + SOCKET_head.Type], ecx
jne .next_socket jne .next_socket
cmp [esi + SOCKET.LocalPort], bx cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
jne .next_socket jne .next_socket
xor ebx, ebx xor ebx, ebx
@ -868,19 +930,18 @@ socket_check_port:
ret ret
;----------------------------------------------- ;-----------------------------------------------
; ;
; SOCKET_internal_receiver ; SOCKET_internal_receiver
; ;
; Checks if any socket wants the received data ; Updates a socket with received data
; If so, update the socket
; ;
; IN: eax = socket number ; Note: the mutex must already be set !
; ecx = number of bytes ;
; esi = pointer to beginning of data ; IN: eax = socket ptr
; dx = Remote port (in INET byte order) ; ecx = size
; edi = IP address of sender ; esi = pointer to buffer
; edi = offset
; ;
; OUT: xxx ; OUT: xxx
; ;
@ -888,39 +949,20 @@ socket_check_port:
align 4 align 4
socket_internal_receiver: socket_internal_receiver:
DEBUGF 1,"internal socket receiver\n" DEBUGF 1,"Internal socket receiver: buffer %x, offset: %x\n", esi, edi
lea ebx, [eax + SOCKET.lock] push edi ; offset
call wait_mutex push ecx ; size
push esi ; data_ptr
mov esi, esp
add_to_queue (eax + 2048), SOCKET_QUEUE_SIZE, 3*4, .full
DEBUGF 1,"Queued packet successfully\n"
add esp, 4*3
mov [eax + SOCKET.RemotePort], dx ; update remote port number mov [eax + SOCKET_head.lock], 0
mov [eax + SOCKET.RemoteIP], edi
mov edx, [eax + SOCKET.rxDataCount] ; get # of bytes already in buffer
DEBUGF 1,"bytes already in socket: %u ", edx
lea edi, [ecx + edx] ; check for buffer overflow
cmp edi, SOCKETBUFFSIZE - SOCKETHEADERSIZE ;
jg .dump ;
lea edi, [eax + SOCKET.rxData + edx]
add [eax + SOCKET.rxDataCount], ecx ; increment the count of bytes in buffer
DEBUGF 1,"adding %u bytes\n", ecx
; copy the data across
push cx
shr ecx, 2
rep movsd
pop cx
and cx, 3
rep movsb
DEBUGF 1,"socket updated\n"
mov [eax + SOCKET.lock], 0
; flag an event to the application ; flag an event to the application
mov edx, [eax + SOCKET.PID] ; get socket owner PID mov edx, [eax + SOCKET_head.PID] ; get socket owner PID
mov ecx, 1 mov ecx, 1
mov esi, TASK_DATA + TASKDATA.pid mov esi, TASK_DATA + TASKDATA.pid
@ -935,18 +977,20 @@ socket_internal_receiver:
.found_pid: .found_pid:
shl ecx, 8 shl ecx, 8
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
mov [check_idle_semaphore], 200 mov [check_idle_semaphore], 200
ret ret
.dump: .full:
mov [eax + SOCKET.lock], 0 DEBUGF 1,"Socket %x is full!\n",eax
mov [eax + SOCKET_head.lock], 0
call kernel_free
add esp, 8
ret ret
; Allocate memory for socket data and put new socket into the list ; Allocate memory for socket data and put new socket into the list
; Newly created socket is initialized with calling PID and number and ; Newly created socket is initialized with calling PID and number and
; put into beginning of list (which is a fastest way). ; put into beginning of list (which is a fastest way).
@ -963,27 +1007,30 @@ proc net_socket_alloc stdcall uses ebx ecx edx edi
; zero-initialize allocated memory ; zero-initialize allocated memory
push eax push eax
mov edi, eax mov edi, eax
mov ecx, SOCKETBUFFSIZE / 4 mov ecx, SOCKETBUFFSIZE / 4
; cld ; cld
xor eax, eax xor eax, eax
rep stosd rep stosd
pop eax pop eax
init_queue (eax + 2048)
; add socket to the list by changing pointers ; add socket to the list by changing pointers
mov ebx, net_sockets mov ebx, net_sockets
push [ebx + SOCKET.NextPtr] push [ebx + SOCKET_head.NextPtr]
mov [ebx + SOCKET.NextPtr], eax mov [ebx + SOCKET_head.NextPtr], eax
mov [eax + SOCKET.PrevPtr], ebx mov [eax + SOCKET_head.PrevPtr], ebx
pop ebx pop ebx
mov [eax + SOCKET.NextPtr], ebx mov [eax + SOCKET_head.NextPtr], ebx
or ebx, ebx or ebx, ebx
jz @f jz @f
mov [ebx + SOCKET.PrevPtr], eax mov [ebx + SOCKET_head.PrevPtr], eax
@@: ; set socket owner PID to the one of calling process @@: ; set socket owner PID to the one of calling process
mov ebx, [TASK_BASE] mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid] mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.PID], ebx mov [eax + SOCKET_head.PID], ebx
; find first free socket number and use it ; find first free socket number and use it
;mov edx, ebx ;mov edx, ebx
@ -992,10 +1039,10 @@ proc net_socket_alloc stdcall uses ebx ecx edx edi
.next_socket_number: .next_socket_number:
inc ecx inc ecx
.next_socket: .next_socket:
mov ebx, [ebx + SOCKET.NextPtr] mov ebx, [ebx + SOCKET_head.NextPtr]
or ebx, ebx or ebx, ebx
jz .last_socket_number jz .last_socket_number
cmp [ebx + SOCKET.Number], ecx cmp [ebx + SOCKET_head.Number], ecx
jne .next_socket jne .next_socket
;cmp [ebx + SOCKET.PID], edx ;cmp [ebx + SOCKET.PID], edx
;jne .next_socket ;jne .next_socket
@ -1003,7 +1050,7 @@ proc net_socket_alloc stdcall uses ebx ecx edx edi
jmp .next_socket_number jmp .next_socket_number
.last_socket_number: .last_socket_number:
mov [eax + SOCKET.Number], ecx mov [eax + SOCKET_head.Number], ecx
.exit: .exit:
ret ret
@ -1025,7 +1072,7 @@ proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD
;mov ecx, [TASK_BASE] ;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid] ;mov ecx, [ecx + TASKDATA.pid]
.next_socket: .next_socket:
mov ebx, [ebx + SOCKET.NextPtr] mov ebx, [ebx + SOCKET_head.NextPtr]
or ebx, ebx or ebx, ebx
jz .error jz .error
cmp ebx, eax cmp ebx, eax
@ -1035,12 +1082,15 @@ proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD
; okay, we found the correct one ; okay, we found the correct one
; remove it from the list first, changing pointers ; remove it from the list first, changing pointers
mov ebx, [eax + SOCKET.NextPtr] mov ebx, [eax + SOCKET_head.NextPtr]
mov eax, [eax + SOCKET.PrevPtr] mov eax, [eax + SOCKET_head.PrevPtr]
mov [eax + SOCKET.NextPtr], ebx mov [eax + SOCKET_head.NextPtr], ebx
or ebx, ebx or ebx, ebx
jz @f jz @f
mov [ebx + SOCKET.PrevPtr], eax mov [ebx + SOCKET_head.PrevPtr], eax
lea ebx, [eax + SOCKET_head.lock]
call wait_mutex
@@: ; and finally free the memory structure used @@: ; and finally free the memory structure used
stdcall kernel_free, [sockAddr] stdcall kernel_free, [sockAddr]
@ -1070,10 +1120,10 @@ proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD
;mov ecx, [TASK_BASE] ;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid] ;mov ecx, [ecx + TASKDATA.pid]
.next_socket: .next_socket:
mov ebx, [ebx + SOCKET.NextPtr] mov ebx, [ebx + SOCKET_head.NextPtr]
or ebx, ebx or ebx, ebx
jz .error jz .error
cmp [ebx + SOCKET.Number], eax cmp [ebx + SOCKET_head.Number], eax
jne .next_socket jne .next_socket
;cmp [ebx + SOCKET.PID], ecx ;cmp [ebx + SOCKET.PID], ecx
;jne .next_socket ;jne .next_socket
@ -1106,7 +1156,7 @@ proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD
;mov ecx, [TASK_BASE] ;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid] ;mov ecx, [ecx + TASKDATA.pid]
.next_socket: .next_socket:
mov ebx, [ebx + SOCKET.NextPtr] mov ebx, [ebx + SOCKET_head.NextPtr]
or ebx, ebx or ebx, ebx
jz .error jz .error
cmp ebx, eax cmp ebx, eax
@ -1115,7 +1165,7 @@ proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD
;jne .next_socket ;jne .next_socket
; okay, we found the correct one ; okay, we found the correct one
mov eax, [ebx + SOCKET.Number] mov eax, [ebx + SOCKET_head.Number]
ret ret
.error: .error:

View File

@ -33,7 +33,7 @@ ETHER equ 1337
ETHER_ARP equ 0x0608 ETHER_ARP equ 0x0608
;AF_UNSPEC equ 0 ;AF_UNSPEC equ 0
;AF_UNIX equ 1 AF_UNIX equ 1
AF_INET4 equ 2 AF_INET4 equ 2
;AF_AX25 equ 3 ;AF_AX25 equ 3
;AF_IPX equ 4 ;AF_IPX equ 4
@ -64,7 +64,7 @@ include "ARP.inc"
include "IPv4.inc" include "IPv4.inc"
include "ethernet.inc" include "ethernet.inc"
include "socket.inc" include "socket.inc"
;include "tcp.inc" include "tcp.inc"
include "udp.inc" include "udp.inc"
include "icmp.inc" include "icmp.inc"
@ -86,6 +86,7 @@ stack_init:
call IPv4_init call IPv4_init
call ARP_init call ARP_init
call UDP_init call UDP_init
call TCP_init
call ICMP_init call ICMP_init
call socket_init call socket_init
@ -115,20 +116,20 @@ stack_handler:
cmp [ETH_RUNNING], 0 cmp [ETH_RUNNING], 0
je .exit je .exit
call ETH_handler ; handle all queued ethernet packets ; Test for 10ms tick
call ETH_send_queued
; Test for 10ms tick, call tcp timer
mov eax, [timer_ticks] mov eax, [timer_ticks]
cmp eax, [last_1hsTick] cmp eax, [last_1hsTick]
je .exit je .exit
mov [last_1hsTick], eax mov [last_1hsTick], eax
; call tcp_tx_handler
call ETH_handler ; handle all queued ethernet packets
call ETH_send_queued
call TCP_send_queued
.sec_tick: .sec_tick:
; Test for 1 second event, call 1s timer functions ; Test for 1 second event
mov al, 0x0 ;second mov al, 0x0 ;second
out 0x70, al out 0x70, al
in al, 0x71 in al, 0x71
@ -139,48 +140,84 @@ stack_handler:
call ARP_decrease_entry_ttls call ARP_decrease_entry_ttls
call IPv4_decrease_fragment_ttls call IPv4_decrease_fragment_ttls
; call tcp_tcb_handler call TCP_decrease_socket_ttls
.exit: .exit:
ret ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Checksum [by Johnny_B]
;; IN:
;; buf_ptr=POINTER to buffer
;; buf_size=SIZE of buffer
;; OUT:
;; AX=16-bit checksum
;; Saves all used registers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
proc checksum_jb stdcall uses ebx esi ecx,\
buf_ptr:DWORD, buf_size:DWORD
xor eax, eax
xor ebx, ebx ;accumulator
mov esi, dword[buf_ptr]
mov ecx, dword[buf_size]
shr ecx, 1 ; ecx=ecx/2
jnc @f ; if CF==0 then size is even number
mov bh, byte[esi + ecx*2]
@@:
cld
.loop: ;-----------------------------------------------------------------
lodsw ;eax=word[esi],esi=esi+2 ;
xchg ah,al ;cause must be a net byte-order ; checksum_1
add ebx, eax ;
loop .loop ; This is the first of two functions needed to calculate the TCP checksum.
;
; IN: edx = start offeset for semi-checksum
; esi = pointer to data
; ecx = data size
; OUT: edx = semi-checksum
;
;-----------------------------------------------------------------
mov eax, ebx align 4
shr eax, 16 checksum_1:
add ax, bx
not ax
ret xor eax, eax
endp shr ecx, 1
pushf
.loop:
lodsw
xchg al, ah
add edx, eax
loop .loop
popf
jnc .end
lodsb
shl ax, 8
add edx, eax
.end:
ret
;-----------------------------------------------------------------
;
; checksum_2
;
; This function calculates the final ip/tcp/udp checksum for you
;
; IN: edx = semi-checksum
; OUT: dx = checksum (in INET byte order)
;
;-----------------------------------------------------------------
align 4
checksum_2:
mov ecx, edx
shr ecx, 16
and edx, 0xffff
add edx, ecx
mov eax, edx
shr eax, 16
add edx, eax
not dx
jnz .not_zero
dec dx
.not_zero:
xchg dl, dh
DEBUGF 1,"Checksum: %x\n",dx
ret
@ -250,6 +287,14 @@ sys_network:
jmp .return jmp .return
@@: @@:
dec bl ; 4 = Get driver pointer
jnz @f
; ..;
@@:
; ... ; 5 Get driver name
.doesnt_exist: .doesnt_exist:
DEBUGF 1,"sys_network: invalid device/function specified!\n" DEBUGF 1,"sys_network: invalid device/function specified!\n"

File diff suppressed because it is too large Load Diff

View File

@ -75,7 +75,33 @@ align 4
UDP_handler: UDP_handler:
DEBUGF 1,"UDP_Handler\n" DEBUGF 1,"UDP_Handler\n"
; TODO: First validate the header & checksum! ; 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 ; Look for a socket where
; IP Packet UDP Destination Port = local Port ; IP Packet UDP Destination Port = local Port
@ -85,14 +111,14 @@ UDP_handler:
.try_more: .try_more:
mov bx , [edx + UDP_Packet.DestinationPort] ; get the local port from the IP Packet's UDP header mov bx , [edx + UDP_Packet.DestinationPort] ; get the local port from the IP Packet's UDP header
.next_socket: .next_socket:
mov eax, [eax + SOCKET.NextPtr] mov eax, [eax + SOCKET_head.NextPtr]
or eax, eax or eax, eax
jz .dump jz .dump
cmp [eax + SOCKET.Domain], AF_INET4 cmp [eax + SOCKET_head.Domain], AF_INET4
jne .next_socket jne .next_socket
cmp [eax + SOCKET.Type], IP_PROTO_UDP cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
jne .next_socket jne .next_socket
cmp [eax + SOCKET.LocalPort], bx cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
jne .next_socket jne .next_socket
DEBUGF 1,"found socket with matching domain, type and localport\n" DEBUGF 1,"found socket with matching domain, type and localport\n"
@ -101,12 +127,12 @@ UDP_handler:
; I will accept the first incoming response to be the one ; 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 ; I bind to, if the socket is opened with a destination IP address of
; 255.255.255.255 ; 255.255.255.255
cmp [eax + SOCKET.RemoteIP], 0xffffffff cmp [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], 0xffffffff
je .ok1 je .ok1
mov ebx, [esp] mov ebx, [esp]
mov ebx, [ebx + ETH_FRAME.Data + IPv4_Packet.SourceAddress] ; get the Source address from the IP Packet FIXME mov ebx, [ebx + ETH_FRAME.Data + IPv4_Packet.SourceAddress] ; get the Source address from the IP Packet FIXME
cmp [eax + SOCKET.RemoteIP], ebx 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 jne .try_more ; Quit if the source IP is not valid, check for more sockets with this IP/PORT combination
@ -115,10 +141,10 @@ UDP_handler:
mov bx, [edx + UDP_Packet.SourcePort] ; Remote port must be 0, or equal to sourceport of packet mov bx, [edx + UDP_Packet.SourcePort] ; Remote port must be 0, or equal to sourceport of packet
cmp [eax + SOCKET.RemotePort], 0 cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], 0
je .ok2 je .ok2
cmp [eax + SOCKET.RemotePort], bx cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx
jne .dump jne .dump
.ok2: .ok2:
@ -130,10 +156,21 @@ UDP_handler:
sub cx , UDP_Packet.Data sub cx , UDP_Packet.Data
mov dx , bx mov dx , bx
call socket_internal_receiver
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] inc [UDP_PACKETS_RX]
pop edi
add esp, 4
sub esi, edi
xchg esi, edi
jmp socket_internal_receiver
.dump: .dump:
DEBUGF 1,"Dumping UDP packet\n" DEBUGF 1,"Dumping UDP packet\n"
call kernel_free call kernel_free
@ -146,69 +183,93 @@ UDP_handler:
;----------------------------------------------------------------- ;-----------------------------------------------------------------
; ;
; Note: UDP works only on top of IP protocol :) ; UDP_socket_send
; ;
; IN: eax = dest ip ; IN: eax = socket pointer
; ebx = source ip ; ecx = number of bytes to send
; ecx = data length ; esi = pointer to data
; edx = remote port shl 16 + local port (both in INET order)
; esi = data offset
; ;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
UDP_create_packet: 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 DEBUGF 1,"Create UDP Packet (size=%u)\n",ecx
push edx esi
add ecx, UDP_Packet.Data
mov di , IP_PROTO_UDP mov di , IP_PROTO_UDP
; dx = fragment id 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
push eax
push ebx
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 call IPv4_create_packet ; TODO: figure out a way to choose between IPv4 and IPv6
cmp edi, -1 cmp edi, -1
je .fail je .fail
mov byte[edi + UDP_Packet.Length], ch mov [esp + 8 + 12], eax ; pointer to buffer start
mov byte[edi + UDP_Packet.Length+1], cl mov [esp + 8 + 12 + 4], edx ; buffer size
sub ecx , UDP_Packet.Data
rol cx, 8
mov [edi + UDP_Packet.Length], cx
mov [esp + 8 + 10], cx
ror cx, 8
pop esi pop esi
push edi push edi ecx
sub ecx, UDP_Packet.Data
add edi, UDP_Packet.Data add edi, UDP_Packet.Data
push cx
shr ecx, 2 shr ecx, 2
rep movsd rep movsd
pop cx mov ecx, [esp]
and cx , 3 and cx , 3
rep movsb rep movsb
pop edi pop ecx edi
pop ecx pop dword [edi + UDP_Packet.SourcePort] ; fill in both portnumbers
mov dword [edi + UDP_Packet.SourcePort], ecx ; notice: we write both port's at once mov [edi + UDP_Packet.Checksum], 0 ; set it to zero, to calculate checksum
mov [edi + UDP_Packet.Checksum], 0 ; Checksum for UDP header + data
xor edx, edx
; TODO: calculate checksum using Pseudo-header (However, using a 0 as checksum shouldnt generate any errors :) mov esi, edi
call checksum_1
; Checksum for pseudoheader
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] inc [UDP_PACKETS_TX]
push edx eax ; TODO: make this work on other protocols besides ethernet
DEBUGF 1,"Sending UDP Packet to device %x\n", ebx ; DEBUGF 1,"Sending UDP Packet to device %x\n", ebx ;
jmp ETH_Sender ; jmp ETH_sender ;
.exit:
ret
.fail: .fail:
; todo: queue the packet ; todo: queue the packet
add esp, 8 add esp, 8+12+8
ret ret
;--------------------------------------------------------------------------- ;---------------------------------------------------------------------------
; ;
; UDP_API ; UDP_API