/kernel/branches/Kolibri-acpi/network/IPv4.inc |
---|
18,7 → 18,7 |
$Revision: 3515 $ |
MAX_FRAGMENTS = 64 |
IPv4_MAX_FRAGMENTS = 64 |
struct IPv4_header |
35,7 → 35,7 |
ends |
struct FRAGMENT_slot |
struct IPv4_FRAGMENT_slot |
ttl dw ? ; Time to live for this entry, 0 for empty slot's |
id dw ? ; Identification field from IP header |
45,7 → 45,7 |
ends |
struct FRAGMENT_entry ; This structure will replace the ethernet header in fragmented ip packets |
struct IPv4_FRAGMENT_entry ; This structure will replace the ethernet header in fragmented ip packets |
PrevPtr dd ? ; Pointer to previous fragment entry (-1 for first packet) |
NextPtr dd ? ; Pointer to next fragment entry (-1 for last packet) |
64,11 → 64,11 |
GATEWAY_LIST rd NET_DEVICES_MAX |
BROADCAST_LIST rd NET_DEVICES_MAX |
IP_packets_tx rd NET_DEVICES_MAX |
IP_packets_rx rd NET_DEVICES_MAX |
IP_packets_dumped rd NET_DEVICES_MAX |
IPv4_packets_tx rd NET_DEVICES_MAX |
IPv4_packets_rx rd NET_DEVICES_MAX |
IPv4_packets_dumped rd NET_DEVICES_MAX |
FRAGMENT_LIST rb MAX_FRAGMENTS * sizeof.FRAGMENT_slot |
IPv4_FRAGMENT_LIST rb IPv4_MAX_FRAGMENTS * sizeof.IPv4_FRAGMENT_slot |
endg |
84,7 → 84,7 |
xor eax, eax |
mov edi, IP_LIST |
mov ecx, 7*NET_DEVICES_MAX + (sizeof.FRAGMENT_slot*MAX_FRAGMENTS)/4 |
mov ecx, 7*NET_DEVICES_MAX + (sizeof.IPv4_FRAGMENT_slot*IPv4_MAX_FRAGMENTS)/4 |
rep stosd |
} |
99,15 → 99,15 |
local .loop, .next |
mov esi, FRAGMENT_LIST |
mov ecx, MAX_FRAGMENTS |
mov esi, IPv4_FRAGMENT_LIST |
mov ecx, IPv4_MAX_FRAGMENTS |
.loop: |
cmp [esi + FRAGMENT_slot.ttl], 0 |
cmp [esi + IPv4_FRAGMENT_slot.ttl], 0 |
je .next |
dec [esi + FRAGMENT_slot.ttl] |
dec [esi + IPv4_FRAGMENT_slot.ttl] |
jz .died |
.next: |
add esi, sizeof.FRAGMENT_slot |
add esi, sizeof.IPv4_FRAGMENT_slot |
dec ecx |
jnz .loop |
jmp .done |
263,7 → 263,7 |
; Now we can update stats |
.ip_ok: |
inc [IP_packets_rx + edi] |
inc [IPv4_packets_rx + edi] |
;---------------------------------- |
; Check if the packet is fragmented |
304,7 → 304,7 |
.dump: |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: dumping\n" |
inc [IP_packets_dumped] ; FIXME: use correct interface |
inc [IPv4_packets_dumped] ; FIXME: use correct interface |
call NET_packet_free |
add esp, 4 ; pop (balance stack) |
ret |
319,7 → 319,7 |
xchg al, ah |
shl ax, 3 |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: fragmented packet offset=%u id=%x\n", ax, [edx + IPv4_header.Identification]:4 |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: fragmented packet offset=%u id=%x ptr=0x%x\n", ax, [edx + IPv4_header.Identification]:4, edx |
test ax, ax ; Is this the first packet of the fragment? |
jz .is_first_fragment |
334,14 → 334,14 |
cmp esi, -1 |
je .dump |
mov [esi + FRAGMENT_slot.ttl], 15 ; Reset the ttl |
mov esi, [esi + FRAGMENT_slot.ptr] |
mov [esi + IPv4_FRAGMENT_slot.ttl], 15 ; Reset the ttl |
mov esi, [esi + IPv4_FRAGMENT_slot.ptr] |
or edi, -1 |
.find_last_entry: ; The following routine will try to find the last entry |
cmp edi, [esi + FRAGMENT_entry.PrevPtr] |
cmp edi, [esi + IPv4_FRAGMENT_entry.PrevPtr] |
jne .destroy_slot ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!) |
mov edi, esi |
mov esi, [esi + FRAGMENT_entry.NextPtr] |
mov esi, [esi + IPv4_FRAGMENT_entry.NextPtr] |
cmp esi, -1 |
jne .find_last_entry |
; We found the last entry (pointer is now in edi) |
348,10 → 348,10 |
; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure |
pop eax ; pointer to packet |
mov [edi + FRAGMENT_entry.NextPtr], eax ; update pointer of previous entry to the new entry |
mov [eax + FRAGMENT_entry.NextPtr], -1 |
mov [eax + FRAGMENT_entry.PrevPtr], edi |
mov [eax + FRAGMENT_entry.Owner], ebx |
mov [edi + IPv4_FRAGMENT_entry.NextPtr], eax ; update pointer of previous entry to the new entry |
mov [eax + IPv4_FRAGMENT_entry.NextPtr], -1 |
mov [eax + IPv4_FRAGMENT_entry.PrevPtr], edi |
mov [eax + IPv4_FRAGMENT_entry.Owner], ebx |
add esp, 4 |
ret |
363,29 → 363,29 |
.is_first_fragment: |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: First fragment packet received!\n" |
; try to locate a free slot.. |
mov ecx, MAX_FRAGMENTS |
mov esi, FRAGMENT_LIST |
mov ecx, IPv4_MAX_FRAGMENTS |
mov esi, IPv4_FRAGMENT_LIST |
.find_free_slot: |
cmp word [esi + FRAGMENT_slot.ttl], 0 |
cmp word [esi + IPv4_FRAGMENT_slot.ttl], 0 |
je .found_free_slot |
add esi, sizeof.FRAGMENT_slot |
add esi, sizeof.IPv4_FRAGMENT_slot |
loop .find_free_slot |
jmp .dump ; If no free slot was found, dump the packet |
.found_free_slot: ; We found a free slot, let's fill in the FRAGMENT_slot structure |
mov [esi + FRAGMENT_slot.ttl], 15 ; RFC recommends 15 secs as ttl |
mov [esi + IPv4_FRAGMENT_slot.ttl], 15 ; RFC recommends 15 secs as ttl |
mov ax, [edx + IPv4_header.Identification] |
mov [esi + FRAGMENT_slot.id], ax |
mov [esi + IPv4_FRAGMENT_slot.id], ax |
mov eax, [edx + IPv4_header.SourceAddress] |
mov [esi + FRAGMENT_slot.SrcIP], eax |
mov [esi + IPv4_FRAGMENT_slot.SrcIP], eax |
mov eax, [edx + IPv4_header.DestinationAddress] |
mov [esi + FRAGMENT_slot.DstIP], eax |
mov [esi + IPv4_FRAGMENT_slot.DstIP], eax |
pop eax |
mov [esi + FRAGMENT_slot.ptr], eax |
mov [esi + IPv4_FRAGMENT_slot.ptr], eax |
; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure |
mov [eax + FRAGMENT_entry.NextPtr], -1 |
mov [eax + FRAGMENT_entry.PrevPtr], -1 |
mov [eax + FRAGMENT_entry.Owner], ebx |
mov [eax + IPv4_FRAGMENT_entry.NextPtr], -1 |
mov [eax + IPv4_FRAGMENT_entry.PrevPtr], -1 |
mov [eax + IPv4_FRAGMENT_entry.Owner], ebx |
add esp, 4 ; balance stack and exit |
ret |
401,33 → 401,33 |
cmp esi, -1 |
je .dump |
mov esi, [esi + FRAGMENT_slot.ptr] ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer |
mov esi, [esi + IPv4_FRAGMENT_slot.ptr] ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer |
push esi |
xor eax, eax |
or edi, -1 |
.count_bytes: |
cmp [esi + FRAGMENT_entry.PrevPtr], edi |
cmp [esi + IPv4_FRAGMENT_entry.PrevPtr], edi |
jne .destroy_slot_pop ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!) |
mov cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.TotalLength] ; Add total length |
mov cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength] ; Add total length |
xchg cl, ch |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx |
add ax, cx |
movzx cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Sub Header length |
movzx cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Sub Header length |
and cx, 0x000F |
shl cx, 2 |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Header size=%u\n", cx |
sub ax, cx |
mov edi, esi |
mov esi, [esi + FRAGMENT_entry.NextPtr] |
mov esi, [esi + IPv4_FRAGMENT_entry.NextPtr] |
cmp esi, -1 |
jne .count_bytes |
mov esi, [esp+4] |
mov [edi + FRAGMENT_entry.NextPtr], esi ; Add this packet to the chain, this simplifies the following code |
mov [esi + FRAGMENT_entry.NextPtr], -1 |
mov [esi + FRAGMENT_entry.PrevPtr], edi |
mov [esi + FRAGMENT_entry.Owner], ebx |
mov [edi + IPv4_FRAGMENT_entry.NextPtr], esi ; Add this packet to the chain, this simplifies the following code |
mov [esi + IPv4_FRAGMENT_entry.NextPtr], -1 |
mov [esi + IPv4_FRAGMENT_entry.PrevPtr], edi |
mov [esi + IPv4_FRAGMENT_entry.Owner], ebx |
mov cx, [edx + IPv4_header.TotalLength] ; Note: This time we dont substract Header length |
xchg cl, ch |
454,18 → 454,18 |
mov edx, [esp+4] ; Get pointer to first fragment entry back in edx |
.rebuild_packet_loop: |
movzx ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset |
movzx ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset |
xchg cl, ch ; intel byte order |
shl cx, 3 ; multiply by 8 and clear first 3 bits |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Fragment offset=%u\n", cx |
lea edi, [eax + ecx] ; Notice that edi will be equal to eax for first fragment |
movzx ebx, [edx + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Find header size (in ebx) of fragment |
movzx ebx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Find header size (in ebx) of fragment |
and bx, 0x000F ; |
shl bx, 2 ; |
lea esi, [edx + sizeof.FRAGMENT_entry] ; Set esi to the correct begin of fragment |
movzx ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.TotalLength] ; Calculate total length of fragment |
lea esi, [edx + sizeof.IPv4_FRAGMENT_entry] ; Set esi to the correct begin of fragment |
movzx ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength] ; Calculate total length of fragment |
xchg cl, ch ; intel byte order |
cmp edi, eax ; Is this packet the first fragment ? |
474,6 → 474,8 |
add esi, ebx ; |
.first_fragment: |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Copying %u bytes from 0x%x to 0x%x\n", ecx, esi, edi |
push cx ; First copy dword-wise, then byte-wise |
shr cx, 2 ; |
rep movsd ; |
482,11 → 484,12 |
rep movsb ; |
push eax |
push [edx + IPv4_FRAGMENT_entry.Owner] ; we need to remeber the owner, in case this is the last packet |
push [edx + IPv4_FRAGMENT_entry.NextPtr] ; Set edx to the next pointer |
push edx ; Push pointer to fragment onto stack |
mov ebx, [edx + FRAGMENT_entry.Owner] ; we need to remeber the owner, in case this is the last packet |
mov edx, [edx + FRAGMENT_entry.NextPtr] ; Set edx to the next pointer |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Next Fragment: 0x%x\n", edx |
call NET_packet_free ; free the previous fragment buffer (this uses the value from stack) |
pop eax |
pop edx ebx eax |
cmp edx, -1 ; Check if it is last fragment in chain |
jne .rebuild_packet_loop |
494,11 → 497,9 |
xchg cl, ch |
mov edx, eax |
mov [edx + IPv4_header.TotalLength], cx |
add esp, 8 |
add esp, 12 |
xchg cl, ch |
push ecx |
push eax |
push ecx edx ; size and pointer |
jmp .handle_it ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr |
.destroy_slot_pop: |
527,19 → 528,19 |
push eax ebx ecx edx |
mov ax, [edx + IPv4_header.Identification] |
mov ecx, MAX_FRAGMENTS |
mov esi, FRAGMENT_LIST |
mov ecx, IPv4_MAX_FRAGMENTS |
mov esi, IPv4_FRAGMENT_LIST |
mov ebx, [edx + IPv4_header.SourceAddress] |
mov edx, [edx + IPv4_header.DestinationAddress] |
.find_slot: |
cmp [esi + FRAGMENT_slot.id], ax |
cmp [esi + IPv4_FRAGMENT_slot.id], ax |
jne .try_next |
cmp [esi + FRAGMENT_slot.SrcIP], ebx |
cmp [esi + IPv4_FRAGMENT_slot.SrcIP], ebx |
jne .try_next |
cmp [esi + FRAGMENT_slot.DstIP], edx |
cmp [esi + IPv4_FRAGMENT_slot.DstIP], edx |
je .found_slot |
.try_next: |
add esi, sizeof.FRAGMENT_slot |
add esi, sizeof.IPv4_FRAGMENT_slot |
loop .find_slot |
or esi, -1 |
552,10 → 553,9 |
; |
; IPv4_output |
; |
; IN: eax = dest ip |
; ebx = output device ptr/0 for automatic choice |
; IN: eax = Destination IP |
; ecx = data length |
; edx = source ip |
; edx = Source IP |
; di = TTL shl 8 + protocol |
; |
; OUT: eax = pointer to buffer start |
573,10 → 573,10 |
cmp ecx, 65500 ; Max IPv4 packet size |
ja .too_large |
push ecx eax edx di |
push ecx di eax |
call IPv4_route ; outputs device number in edi, dest ip in eax, source IP in edx |
push edx |
call IPv4_route ; outputs device number in edi, dest ip in eax |
test edi, edi |
jz .loopback |
586,12 → 586,12 |
push ebx ; push the mac onto the stack |
push ax |
inc [IP_packets_tx + edi] ; update stats |
inc [IPv4_packets_tx + edi] ; update stats |
mov ebx, [NET_DRV_LIST + edi] |
lea eax, [ebx + ETH_DEVICE.mac] |
mov edx, esp |
mov ecx, [esp + 10 + 6] |
mov ecx, [esp + 6 + 8 + 2] |
add ecx, sizeof.IPv4_header |
mov di, ETHER_PROTO_IPv4 |
call ETH_output |
605,12 → 605,14 |
mov [edi + IPv4_header.TotalLength], cx |
mov [edi + IPv4_header.Identification], 0 ; fragment id: FIXME |
mov [edi + IPv4_header.FlagsAndFragmentOffset], 0 |
pop word [edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol |
; [edi + IPv4_header.Protocol] |
mov [edi + IPv4_header.HeaderChecksum], 0 |
popd [edi + IPv4_header.SourceAddress] |
popd [edi + IPv4_header.DestinationAddress] |
pop word[edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol |
; [edi + IPv4_header.Protocol] |
pop ecx |
IPv4_checksum edi |
677,7 → 679,7 |
push ebx ; push the mac |
push ax |
inc [IP_packets_tx + 4*edi] |
inc [IPv4_packets_tx + 4*edi] |
mov ebx, [NET_DRV_LIST + 4*edi] |
lea eax, [ebx + ETH_DEVICE.mac] |
mov edx, esp |
857,40 → 859,44 |
; IPv4_route |
; |
; IN: eax = Destination IP |
; OUT: edi = device number*4 |
; eax = ip of gateway if nescessary, unchanged otherwise |
; edx = Source IP |
; OUT: eax = Destination IP (or gateway IP) |
; edx = Source IP |
; edi = device number*4 |
; DESTROYED: |
; ecx |
; |
;--------------------------------------------------------------------------- |
align 4 |
IPv4_route: |
IPv4_route: ; TODO: return error if no valid route found |
cmp eax, 0xffffffff |
je .broadcast |
xor edi, edi |
mov ecx, NET_DEVICES_MAX |
.loop: |
mov ebx, [IP_LIST+edi] |
and ebx, [SUBNET_LIST+edi] |
jz .next |
mov edx, eax |
and edx, [SUBNET_LIST+edi] |
cmp ebx, edx |
jne .next |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi |
ret |
mov ecx, eax |
and ecx, [SUBNET_LIST + edi] |
cmp ebx, ecx |
je .got_it |
.next: |
add edi, 4 |
dec ecx |
jnz .loop |
cmp edi, 4*NET_DEVICES_MAX |
jb .loop |
.invalid: |
mov eax, [GATEWAY_LIST+4] ;;; FIXME |
mov eax, [GATEWAY_LIST + 4] ; TODO: let user (or a user space daemon) configure default route |
.broadcast: |
mov edi, 4 ; if none found, use device 1 as default ;;;; FIXME |
mov edi, 4 ; TODO: same as above |
.got_it: |
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi |
test edx, edx |
jnz @f |
mov edx, [IP_LIST + edi] |
@@: |
ret |
910,6 → 916,45 |
ret |
;----------------------------------------------------------------- |
; |
; IPv4_connect |
; |
; IN: eax = socket pointer |
; OUT: eax = 0 ok / -1 error |
; ebx = error code |
; |
;------------------------- |
align 4 |
IPv4_connect: |
push eax edx |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
pop edx eax |
; Fill in local IP |
cmp [eax + IP_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST + 4] ; FIXME: use correct local IP |
pop [eax + IP_SOCKET.LocalIP] |
; Fill in remote IP |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
; Set up data receiving queue |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) |
pop eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
xor eax, eax |
ret |
;--------------------------------------------------------------------------- |
; |
; IPv4_API |
952,11 → 997,11 |
ret |
.packets_tx: |
mov eax, [IP_packets_tx + eax] |
mov eax, [IPv4_packets_tx + eax] |
ret |
.packets_rx: |
mov eax, [IP_packets_rx + eax] |
mov eax, [IPv4_packets_rx + eax] |
ret |
.read_ip: |
/kernel/branches/Kolibri-acpi/network/ethernet.inc |
---|
17,6 → 17,7 |
$Revision: 3346 $ |
ETH_FRAME_MINIMUM = 60 |
ETH_QUEUE_SIZE = 255 |
struct ETH_header |
32,6 → 33,14 |
ends |
struct ETH_queue_entry |
device dd ? |
packet dd ? |
size dd ? |
ends |
iglobal |
align 4 |
38,6 → 47,26 |
ETH_BROADCAST dp 0xffffffffffff |
endg |
uglobal |
align 4 |
ETH_input_event dd ? |
ETH_queue rd (ETH_QUEUE_SIZE*sizeof.ETH_queue_entry + sizeof.queue)/4 |
endg |
macro ETH_init { |
init_queue ETH_queue |
movi ebx, 1 |
mov ecx, ETH_process_input |
call new_sys_threads |
test eax, eax |
jns @f |
DEBUGF DEBUG_NETWORK_ERROR,'K : cannot create kernel thread for ethernet, error %d\n', eax |
@@: |
} |
;----------------------------------------------------------------- |
; |
; ETH_input |
53,9 → 82,61 |
;----------------------------------------------------------------- |
align 4 |
ETH_input: |
mov eax, [esp] |
mov ecx, [esp+4] |
push ebx |
mov esi, esp |
pushf |
cli |
add_to_queue ETH_queue, ETH_QUEUE_SIZE, sizeof.ETH_queue_entry, .fail |
popf |
add esp, sizeof.ETH_queue_entry |
xor edx, edx |
mov eax, [ETH_input_event] |
mov ebx, [eax + EVENT.id] |
xor esi, esi |
call raise_event |
ret |
.fail: |
popf |
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH incoming queue is full, discarding packet!\n" |
add esp, sizeof.ETH_queue_entry - 8 |
call NET_packet_free |
add esp, 4 |
ret |
align 4 |
ETH_process_input: |
xor esi, esi |
mov ecx, MANUAL_DESTROY |
call create_event |
mov [ETH_input_event], eax |
.wait: |
mov eax, [ETH_input_event] |
mov ebx, [eax + EVENT.id] |
call wait_event |
.loop: |
get_from_queue ETH_queue, ETH_QUEUE_SIZE, sizeof.ETH_queue_entry, .wait |
mov eax, [esi + ETH_queue_entry.packet] |
mov ecx, [esi + ETH_queue_entry.size] |
mov ebx, [esi + ETH_queue_entry.device] |
pushd .loop ; return address |
push ecx eax |
DEBUGF DEBUG_NETWORK_VERBOSE,"ETH_input: size=%u\n", ecx |
sub ecx, sizeof.ETH_header |
jb .dump |
78,7 → 159,7 |
cmp ax, ETHER_PROTO_PPP_SESSION |
je PPPoE_session_input |
DEBUGF DEBUG_NETWORK_ERROR, "ETH_input: Unknown packet type=%x\n", ax |
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_input: Unknown packet type=%x\n", ax |
.dump: |
DEBUGF DEBUG_NETWORK_VERBOSE,"ETH_input: dumping\n" |
/kernel/branches/Kolibri-acpi/network/icmp.inc |
---|
310,15 → 310,16 |
ret |
if 0 |
;----------------------------------------------------------------- |
; |
; ICMP_output |
; |
; IN: eax = dest ip |
; ebx = source ip |
; bh = type |
; bl = code |
; ecx = data length |
; dh = type |
; dl = code |
; edx = source ip |
; esi = data offset |
; edi = identifier shl 16 + sequence number |
; |
328,10 → 329,7 |
DEBUGF DEBUG_NETWORK_VERBOSE, "Creating ICMP Packet\n" |
push esi edi dx |
mov edx, [eax + IP_SOCKET.LocalIP] |
mov eax, [eax + IP_SOCKET.RemoteIP] |
push esi edi bx |
add ecx, sizeof.ICMP_header |
mov di, IP_PROTO_ICMP SHL 8 + 128 ; TTL |
call IPv4_output |
374,6 → 372,7 |
DEBUGF DEBUG_NETWORK_ERROR, "Creating ICMP Packet failed\n" |
add esp, 2*4 + 2 |
ret |
end if |
380,7 → 379,7 |
;----------------------------------------------------------------- |
; |
; ICMP_output |
; ICMP_output_raw |
; |
; IN: eax = socket ptr |
; ecx = data length |
/kernel/branches/Kolibri-acpi/network/socket.inc |
---|
39,6 → 39,7 |
snd_proc dd ? |
rcv_proc dd ? |
connect_proc dd ? |
ends |
131,6 → 132,7 |
timer_persist dd ? |
timer_keepalive dd ? ; keepalive/syn timeout |
timer_timed_wait dd ? ; also used as 2msl timer |
timer_connect dd ? |
; extra |
142,6 → 144,7 |
temp_bits db ? |
rb 3 ; align |
ends |
struct UDP_SOCKET IP_SOCKET |
148,7 → 151,6 |
LocalPort dw ? ; network byte order |
RemotePort dw ? ; network byte order |
firstpacket db ? |
ends |
309,6 → 311,7 |
mov [eax + SOCKET.Domain], ecx |
mov [eax + SOCKET.Type], edx |
mov [eax + SOCKET.Protocol], esi |
mov [eax + SOCKET.connect_proc], connect_notsupp |
cmp ecx, AF_INET4 |
jne .no_inet4 |
357,6 → 360,7 |
mov [eax + SOCKET.Protocol], IP_PROTO_UDP |
mov [eax + SOCKET.snd_proc], SOCKET_send_udp |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
mov [eax + SOCKET.connect_proc], UDP_connect |
ret |
align 4 |
364,6 → 368,7 |
mov [eax + SOCKET.Protocol], IP_PROTO_TCP |
mov [eax + SOCKET.snd_proc], SOCKET_send_tcp |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_stream |
mov [eax + SOCKET.connect_proc], TCP_connect |
TCP_init_socket eax |
ret |
373,6 → 378,7 |
.raw_ip: |
mov [eax + SOCKET.snd_proc], SOCKET_send_ip |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
mov [eax + SOCKET.connect_proc], IPv4_connect |
ret |
380,6 → 386,7 |
.raw_icmp: |
mov [eax + SOCKET.snd_proc], SOCKET_send_icmp |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
mov [eax + SOCKET.connect_proc], IPv4_connect |
ret |
align 4 |
414,6 → 421,9 |
cmp esi, 2 |
jb .invalid |
cmp [eax + UDP_SOCKET.LocalPort], 0 ; Socket can only be bound once |
jnz .invalid |
cmp word [edx], AF_INET4 |
je .af_inet4 |
449,17 → 459,21 |
.tcp: |
.udp: |
mov ebx, [edx + 4] ; First, fill in the IP |
test ebx, ebx ; If IP is 0, use default |
jnz @f |
mov ebx, [IP_LIST + 4] ;;;;; FIXME !i!i!i |
@@: |
mov [eax + IP_SOCKET.LocalIP], ebx |
mov bx, [edx + 2] ; Now fill in the local port if it's still available |
call SOCKET_check_port |
jz .addrinuse ; ZF is set by socket_check_port, on error |
pushd [edx + 4] ; First, fill in the IP |
popd [eax + IP_SOCKET.LocalIP] |
mov bx, [edx + 2] ; Did caller specify a local port? |
test bx, bx |
jnz .just_check |
call SOCKET_find_port ; Nope, find an ephemeral one |
jmp .done |
.just_check: |
call SOCKET_check_port ; Yes, check if it's still available |
jz .addrinuse ; ZF is set by socket_check_port on error |
.done: |
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_bind: local ip=%u.%u.%u.%u\n",\ |
[eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\ |
[eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1 |
496,9 → 510,19 |
cmp esi, 8 |
jb .invalid |
cmp word [edx], AF_INET4 |
je .af_inet4 |
cmp [eax + SOCKET.state], SS_ISCONNECTING |
je .already |
test [eax + SOCKET.options], SO_ACCEPTCON |
jnz .notsupp |
call [eax + SOCKET.connect_proc] |
mov dword[esp+20], ebx |
mov dword[esp+32], eax |
ret |
.notsupp: |
mov dword[esp+20], EOPNOTSUPP |
mov dword[esp+32], -1 |
509,153 → 533,19 |
mov dword[esp+32], -1 |
ret |
.af_inet4: |
cmp [eax + IP_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST + 4] ; FIXME !i!i!i! |
pop [eax + IP_SOCKET.LocalIP] |
@@: |
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
je .udp |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
je .tcp |
cmp [eax + SOCKET.Protocol], IP_PROTO_IP |
je .ip |
cmp [eax + SOCKET.Protocol], IP_PROTO_ICMP |
je .ip |
jmp .notsupp |
align 4 |
.udp: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pushw [edx + 2] |
pop [eax + UDP_SOCKET.RemotePort] |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
cmp [eax + UDP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
@@: |
mov [eax + UDP_SOCKET.firstpacket], 0 |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue |
pop eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
mov dword[esp+32], 0 |
ret |
align 4 |
.tcp: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pushw [edx + 2] |
pop [eax + TCP_SOCKET.RemotePort] |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
cmp [eax + TCP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
@@: |
mov [eax + TCP_SOCKET.timer_persist], 0 |
mov [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT |
push [TCP_sequence_num] |
add [TCP_sequence_num], 6400 |
pop [eax + TCP_SOCKET.ISS] |
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init |
TCP_sendseqinit eax |
; mov [ebx + TCP_SOCKET.timer_retransmission], ;; todo: create macro to set retransmission timer |
mov ebx, eax |
lea eax, [ebx + STREAM_SOCKET.snd] |
call SOCKET_ring_create ; TODO: check if memory was available or not |
lea eax, [ebx + STREAM_SOCKET.rcv] |
call SOCKET_ring_create ; TODO: same here |
pusha |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
popa |
push ebx |
mov eax, ebx |
call TCP_output |
pop eax |
.block: |
test [eax + SOCKET.options], SO_NONBLOCK |
jz .loop |
mov dword[esp+20], EWOULDBLOCK |
.already: |
mov dword[esp+20], EALREADY |
mov dword[esp+32], -1 |
ret |
.loop: |
cmp [eax + TCP_SOCKET.t_state], TCPS_CLOSED |
je .fail |
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED |
je .established |
ja .fail |
call SOCKET_block |
jmp .loop |
.fail: |
mov eax, [eax + SOCKET.errorcode] |
mov [esp+20], eax |
mov dword[esp+32], -1 |
connect_notsupp: |
xor eax, eax |
dec eax |
mov ebx, EOPNOTSUPP |
ret |
.established: |
mov dword[esp+32], 0 |
ret |
align 4 |
.ip: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue |
pop eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
mov dword[esp+32], 0 |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_listen |
865,6 → 755,9 |
call [eax + SOCKET.rcv_proc] |
pop edi |
test [eax + SOCKET.state], SS_CANTRCVMORE |
jnz .return |
cmp ebx, EWOULDBLOCK |
jne .return |
871,9 → 764,6 |
test edi, MSG_DONTWAIT |
jnz .return_err |
test [eax + SOCKET.state], SS_CANTRCVMORE |
jnz .return_err |
; test [eax + SOCKET.options], SO_NONBLOCK |
; jnz .return_err |
885,10 → 775,10 |
push EINVAL |
pop ebx |
.return_err: |
mov eax, -1 |
mov ecx, -1 |
.return: |
mov [esp+20], ebx |
mov [esp+32], eax |
mov [esp+32], ecx |
ret |
909,7 → 799,7 |
cmp ecx, ebx ; If data segment does not fit in applications buffer, abort |
ja .too_small |
push ecx |
push eax ecx |
push [esi + socket_queue_entry.buf_ptr] ; save the buffer addr so we can clear it later |
mov esi, [esi + socket_queue_entry.data_ptr] |
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi |
930,12 → 820,12 |
.nd: |
call NET_packet_free |
pop eax ; return number of bytes copied to application |
pop ecx eax ; return number of bytes copied to application |
xor ebx, ebx |
ret |
.too_small: |
mov eax, -1 |
mov ecx, -1 |
push EMSGSIZE |
pop ebx |
ret |
980,11 → 870,12 |
mov edi, edx |
xor edx, edx |
push eax |
add eax, STREAM_SOCKET.rcv |
call SOCKET_ring_read ; copy data from kernel buffer to application buffer |
call SOCKET_ring_free ; free read memory |
pop eax |
mov eax, ecx ; return number of bytes copied |
xor ebx, ebx ; errorcode = 0 (no error) |
ret |
991,10 → 882,11 |
.wouldblock: |
push EWOULDBLOCK |
pop ebx |
xor ecx, ecx |
ret |
.peek: |
mov eax, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size] |
mov ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size] |
xor ebx, ebx |
ret |
2193,6 → 2085,7 |
mov eax, [eax + SOCKET.NextPtr] |
or eax, eax |
jz .error |
diff16 "tetten", 0, $ |
cmp [eax + SOCKET.Number], ecx |
jne .next_socket |
2321,6 → 2214,11 |
align 4 |
SOCKET_process_end: |
cmp [net_sockets + SOCKET.NextPtr], 0 ; Are there any active sockets at all? |
je .quickret ; nope, exit immediately |
; TODO: run the following code in another thread, to avoid deadlock |
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: %x\n", edx |
pusha |
2371,6 → 2269,7 |
call mutex_unlock |
popa |
.quickret: |
ret |
2390,10 → 2289,10 |
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_is_connecting: %x\n", eax |
and [eax + SOCKET.options], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING) |
or [eax + SOCKET.options], SS_ISCONNECTING |
and [eax + SOCKET.state], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING) |
or [eax + SOCKET.state], SS_ISCONNECTING |
jmp SOCKET_notify |
ret |
/kernel/branches/Kolibri-acpi/network/stack.inc |
---|
115,6 → 115,7 |
; Error Codes |
ENOBUFS = 1 |
EINPROGRESS = 2 |
EOPNOTSUPP = 4 |
EWOULDBLOCK = 6 |
ENOTCONN = 9 |
125,6 → 126,7 |
EADDRINUSE = 20 |
ECONNREFUSED = 61 |
ECONNRESET = 52 |
EISCONN = 56 |
ETIMEDOUT = 60 |
ECONNABORTED = 53 |
248,6 → 250,8 |
mov ecx, (NET_DEVICES_MAX + 2) |
rep stosd |
ETH_init |
PPPoE_init |
IPv4_init |
/kernel/branches/Kolibri-acpi/network/tcp.inc |
---|
71,6 → 71,8 |
TCP_time_srtt_default = 0 ; |
TCP_time_max_idle = 8*TCP_time_keep_interval ; FIXME |
TCP_time_connect = 300 ; in 1/100s (default=3s) |
; timer constants |
TCP_max_rxtshift = 12 ; max retransmissions waiting for ACK |
TCP_max_keepcnt = 8 ; max keepalive probes |
/kernel/branches/Kolibri-acpi/network/tcp_output.inc |
---|
437,8 → 437,6 |
; Create the IP packet |
mov ecx, esi |
mov ebx, [eax + SOCKET.device] |
mov edx, [eax + IP_SOCKET.LocalIP] ; source ip |
mov eax, [eax + IP_SOCKET.RemoteIP] ; dest ip |
mov di, IP_PROTO_TCP shl 8 + 128 |
/kernel/branches/Kolibri-acpi/network/tcp_usreq.inc |
---|
74,8 → 74,139 |
ret |
;------------------------- |
; |
; TCP_connect |
; |
; IN: eax = socket ptr |
; OUT: eax = 0 ok / -1 error |
; ebx = error code |
; |
;------------------------- |
align 4 |
TCP_connect: |
test [eax + SOCKET.state], SS_ISCONNECTED |
jnz .eisconn |
push eax edx |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
pop edx eax |
; Fill in local IP |
cmp [eax + IP_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST + 4] ; FIXME: use correct local IP |
pop [eax + IP_SOCKET.LocalIP] |
; Fill in remote port and IP |
pushw [edx + 2] |
pop [eax + TCP_SOCKET.RemotePort] |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
; Find a local port, if user didnt define one |
cmp [eax + TCP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
@@: |
; Start the TCP sequence |
mov [eax + TCP_SOCKET.timer_persist], 0 |
mov [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT |
push [TCP_sequence_num] |
add [TCP_sequence_num], 6400 |
pop [eax + TCP_SOCKET.ISS] |
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init |
TCP_sendseqinit eax |
mov ebx, eax |
lea eax, [ebx + STREAM_SOCKET.snd] |
call SOCKET_ring_create |
test eax, eax |
jz .nomem |
lea eax, [ebx + STREAM_SOCKET.rcv] |
call SOCKET_ring_create |
test eax, eax |
jz .nomem |
push ebx |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
pop eax |
call SOCKET_is_connecting |
; Now send the SYN packet to remote end |
push eax |
call TCP_output |
pop eax |
.block: |
test [eax + SOCKET.options], SO_NONBLOCK |
jz .waitforit |
xor eax, eax |
dec eax |
mov ebx, EINPROGRESS |
ret |
.nomem: |
xor eax, eax |
dec eax |
mov ebx, ENOMEM |
ret |
.eisconn: |
xor eax, eax |
dec eax |
mov ebx, EISCONN |
ret |
.waitforit: |
push eax |
stdcall timer_hs, TCP_time_connect, 0, .timeout, eax |
pop ebx |
mov [ebx + TCP_SOCKET.timer_connect], eax |
mov eax, ebx |
.loop: |
cmp [eax + SOCKET.errorcode], 0 |
jne .fail |
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED |
je .established |
call SOCKET_block |
jmp .loop |
.timeout: |
mov eax, [esp+4] |
mov [eax + SOCKET.errorcode], ETIMEDOUT |
and [eax + SOCKET.state], not SS_ISCONNECTING |
call SOCKET_notify.unblock |
ret 4 |
.fail: |
mov ebx, [eax + SOCKET.errorcode] |
mov [eax + SOCKET.errorcode], 0 ; Clear the error, we only need to send it to the caller once |
xor eax, eax |
dec eax |
ret |
.established: |
stdcall cancel_timer_hs, [eax + TCP_SOCKET.timer_connect] |
xor eax, eax |
ret |
;------------------------- |
; |
; TCP_disconnect |
/kernel/branches/Kolibri-acpi/network/udp.inc |
---|
182,7 → 182,7 |
; |
; FIXME: UDP should check remote IP, but not under all circumstances! |
cmp [eax + UDP_SOCKET.firstpacket], 0 |
cmp [eax + UDP_SOCKET.RemotePort], 0 |
je .updateport |
cmp [eax + UDP_SOCKET.RemotePort], cx |
211,8 → 211,6 |
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: new remote port=%x\n", cx ; FIXME: find a way to print big endian values with debugf |
mov [eax + UDP_SOCKET.RemotePort], cx |
inc [eax + UDP_SOCKET.firstpacket] |
jmp .updatesock |
.dump_: |
262,7 → 260,6 |
sub esp, 8 ; Data ptr and data size will be placed here |
push edx esi |
mov ebx, [eax + SOCKET.device] |
mov edx, [eax + IP_SOCKET.LocalIP] |
mov eax, [eax + IP_SOCKET.RemoteIP] |
mov di, IP_PROTO_UDP shl 8 + 128 |
311,6 → 308,84 |
;----------------------------------------------------------------- |
; |
; UDP_connect |
; |
; IN: eax = socket pointer |
; OUT: eax = 0 ok / -1 error |
; ebx = error code |
; |
;------------------------- |
align 4 |
UDP_connect: |
test [eax + SOCKET.state], SS_ISCONNECTED |
jz @f |
call UDP_disconnect |
@@: |
push eax edx |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
pop edx eax |
; Fill in local IP |
cmp [eax + IP_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST + 4] ; FIXME: use correct local IP |
pop [eax + IP_SOCKET.LocalIP] |
; Fill in remote port and IP, overwriting eventually previous values |
pushw [edx + 2] |
pop [eax + UDP_SOCKET.RemotePort] |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
; Find a local port, if user didnt define one |
cmp [eax + UDP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
@@: |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue |
pop eax |
push eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
pop eax |
call SOCKET_is_connected |
xor eax, eax |
ret |
;----------------------------------------------------------------- |
; |
; UDP_disconnect |
; |
; IN: eax = socket pointer |
; OUT: eax = socket pointer |
; |
;------------------------- |
align 4 |
UDP_disconnect: |
; TODO: remove the pending received data |
call SOCKET_is_disconnected |
ret |
;--------------------------------------------------------------------------- |
; |
; UDP_API |