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

View File

@ -56,13 +56,13 @@
include 'macros.inc' include 'macros.inc'
$Revision: 1025 $ $Revision$
USE_COM_IRQ equ 1 ; make irq 3 and irq 4 available for PCI devices USE_COM_IRQ equ 1 ; make irq 3 and irq 4 available for PCI devices
; Enabling the next line will enable serial output console ; Enabling the next line will enable serial output console
;debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used
include "proc32.inc" include "proc32.inc"
include "kglobals.inc" include "kglobals.inc"

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
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) 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
@ -202,13 +260,14 @@ socket_bind:
.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,13 +308,13 @@ 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
@ -263,11 +322,11 @@ socket_connect:
.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
@ -275,6 +334,7 @@ socket_connect:
.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
@ -939,14 +981,16 @@ socket_internal_receiver:
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 ; checksum_1
;; OUT: ;
;; AX=16-bit checksum ; This is the first of two functions needed to calculate the TCP checksum.
;; Saves all used registers ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; IN: edx = start offeset for semi-checksum
proc checksum_jb stdcall uses ebx esi ecx,\ ; esi = pointer to data
buf_ptr:DWORD, buf_size:DWORD ; ecx = data size
; OUT: edx = semi-checksum
;
;-----------------------------------------------------------------
align 4
checksum_1:
xor eax, eax xor eax, eax
xor ebx, ebx ;accumulator shr ecx, 1
mov esi, dword[buf_ptr] pushf
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: .loop:
lodsw ;eax=word[esi],esi=esi+2 lodsw
xchg ah,al ;cause must be a net byte-order xchg al, ah
add ebx, eax add edx, eax
loop .loop loop .loop
mov eax, ebx popf
shr eax, 16 jnc .end
add ax, bx
not ax 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 ret
endp
@ -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