Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 2930 → Rev 2931

/kernel/branches/net/network/PPPoE.inc
1,155 → 1,136
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2009-2012. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2012. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Clevermouse & hidnplayr ;;
;; PPPoE.INC ;;
;; ;;
;; Part of the tcp/ip network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
struct PPPoE_frame
 
struct PPPoE_header
 
VersionAndType db ?
Code db ?
SessionID dw ?
Length dw ? ; Length of payload, does NOT include the length PPPoE header.
Payload rb 0
 
ends
 
struct PPPoE_connection
 
next dd ? ; pointer to next connection
prev dd ? ; pointer to previous connection
uglobal
 
pid dd ? ; identifier of base application
PPPoE_SID dw ?
PPPoE_MAC dp ?
 
datalen dd ? ; length of received data
recvbuf rb 1500 ; buffer for received data
sendbuf rb 1500 ; buffer for data to send
 
ends
 
iglobal
align 4
PPPoE.head dd PPPoE.head
PPPoE.tail dd PPPoE.head
endg
 
uglobal
PPPoE.cur_receiver dd ?
PPPoE.cur_receiver_ptr dd ?
PPPoE.cur_receiver_len dd ?
endg
 
 
; Allocates internal structure for future PPPoE actions.
;-----------------------------------------------------------------
;
; PPPoE discovery input
;
; Handler of received Ethernet packet with type = Discovery
;
;
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
; pointer to device struct in ebx
; pointer to PPP header in edx
; size of PPP packet in ecx
; OUT: /
;
;-----------------------------------------------------------------
align 4
PPPoE_alloc_connection:
PPPoE_discovery_input:
 
; 1. Allocate memory in the kernel area.
stdcall kernel_alloc, sizeof.PPPoE_connection
DEBUGF 2,"PPPoE_discovery_input\n"
 
; 1a. If memory allocation failed, return NULL.
test eax, eax
jz .nothing
; First, find open PPPoE socket
 
; 2. Copy PID of caller to the structure.
mov edx, [CURRENT_TASK]
mov [eax + PPPoE_connection.pid], edx
mov eax, net_sockets
 
; 3. Insert the structure to the list of all connections.
mov [eax + PPPoE_connection.next], PPPoE.head
mov edx, [PPPoE.tail]
mov [eax + PPPoE_connection.prev], edx
mov [edx + PPPoE_connection.next], eax
mov [PPPoE.tail], eax
.next_socket:
mov eax, [eax + SOCKET.NextPtr]
or eax, eax
jz .dump
 
.nothing:
ret
cmp [eax + SOCKET.Domain], AF_PPP
jne .next_socket
 
cmp [eax + SOCKET.Protocol], PPP_PROTO_ETHERNET
jne .next_socket
 
align 4
PPPoE_free_connection:
; Now, send it to the this socket
 
; 1. Check that the caller is the owner of this connection.
mov eax, [CURRENT_TASK]
cmp [ebx+PPPoE_connection.pid], eax
jnz .nothing
mov ecx, [esp + 4]
mov esi, [esp]
 
; 2. Delete the structure from the list of all connections.
mov eax, [ebx+PPPoE_connection.next]
mov edx, [ebx+PPPoE_connection.prev]
mov [eax+PPPoE_connection.prev], edx
mov [edx+PPPoE_connection.next], eax
jmp SOCKET_input
 
; 3. Free the memory.
stdcall kernel_free, ebx
 
.nothing:
.dump:
DEBUGF 1,'PPPoE_discovery_input: dumping\n'
call kernel_free
add esp, 4
ret
 
 
; Send PADI packet
 
; ebx (ecx in app) = size of buffer for PPPoE offers, must be at least 1514
; ecx (edx in app) = size of tags, 0 means "use default"
; edx (esi in app) = pointer to buffer for PPPoE offers
; esi (edi in app) = pointer to tags, ignored if 'size of tags' == 0
;--------------------------------------
;
; Send discovery packet
;
; ebx (ecx in app) = device
; ecx (edx in app) = size packet
; edx (esi in app) = pointer to packet
;
;--------------------------------------
align 4
PPPoE_send_init:
PPPoE_discovery_output:
 
; 1. Check length.
cmp ebi, 1514
jb .bad
 
; RFC2516: An entire PADI packet (including the PPPoE header) MUST NOT
; exceed 1484 octets.
; PPPoE header is 6 bytes long, so maximum length of tags is 1478.
cmp ecx, 1478
cmp ecx, 1484 + 14
ja .bad
 
; 2. Check that no one listen for offers.
cmp [PPPoE.cur_receiver], 0
jnz .bad
; Check that device exists and is ethernet device
cmp ebx, MAX_NET_DEVICES
ja .bad
 
; 3. Remember PID and data pointer of current listener.
push [CURRENT_TASK]
pop [PPPoE.cur_receiver]
mov [PPPoE.cur_receiver_ptr], edx
mov [PPPoE.cur_receiver_len], ebx
and dword [edx], 0 ; no offers yet
mov ebx, [NET_DRV_LIST + 4*ebx]
test ebx, ebx
jz .bad
 
; 4. Create packet.
test ecx, ecx
jnz @f
mov esi, .default_payload
mov ecx, .default_payload_length
@@:
cmp [ebx + NET_DEVICE.type], NET_TYPE_ETH
jne .bad
 
mov edx, [NET_DRV_LIST] ;;;; FIXME
lea eax, [ebx + ETH_DEVICE.mac] ; Source Address
mov edx, ETH_BROADCAST ; Destination Address
add ecx, sizeof.PPPoE_header ; Data size
mov di, ETHER_PPP_DISCOVERY ; Protocol
call ETH_output
jz .eth_error
; Create packet.
stdcall kernel_alloc, 1500
test eax, eax
jz .bad
 
push edx eax
push ecx eax
 
; 4b. Set ver=1, type=1 (=> first byte 0x11), code=9 (PADI packet), session=0
mov dword [edi], (0x09 shl 8) + 0x11
mov edi, eax
rep movsb
 
; 4c. Set payload length.
mov [edi+4], ch
mov [edi+5], cl
; Overwrite source MAC and protocol type
lea edi, [eax + ETH_header.SrcMAC]
lea esi, [ebx + ETH_DEVICE.mac]
movsd
movsw
mov ax, ETHER_PPP_DISCOVERY
stosw
 
; 4e. Copy given tags.
rep movsb
; And send the packet
call [ebx + NET_DEVICE.transmit]
 
; 5. Send packet.
call [ebx + NET_DEVICE.transmit]
; 6. Return.
xor eax, eax
ret
 
157,97 → 138,140
or eax, -1
ret
 
.default_payload:
; Service-Name tag with zero length
dw 0x0101, 0x0000
.default_payload_length = $ - .default_payload
 
 
; Stop receiving PADO packets
;-----------------------------------------------------------------
;
; PPPoE session input
;
; Handler of received Ethernet packet with type = Session
;
;
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
; pointer to device struct in ebx
; pointer to PPP header in edx
; size of PPP packet in ecx
; OUT: /
;
;-----------------------------------------------------------------
align 4
PPPoE_stop_offers:
PPPoE_session_input:
 
; Only the listener can stop listen. ;;; TODO: make sure this function is called when process gets terminated
mov eax, [CURRENT_TASK]
cmp [PPPoE.cur_receiver], eax
jnz .bad
xor eax, eax
mov [PPPoE.cur_receiver_ptr], eax
mov [PPPoE.cur_receiver], eax
ret
cmp [edx + PPPoE_frame.VersionAndType], 0x11
jne .dump
 
.bad:
or eax, -1
ret
cmp [edx + PPPoE_frame.Code], 0x00
jne .dump
 
; Send PPPoE data in Discovery stage
align 4
PPPoE_send_discovery:
ret
movzx ecx, [edx + PPPoE_frame.Length]
xchg cl, ch
 
; Receive PPPoE data in Discovery stage
align 4
PPPoE_receive_discovery:
mov ax, [edx + PPPoE_frame.SessionID]
DEBUGF 2,"PPPoE_input: session ID=%x, length=%u\n", ax, cx
cmp ax, [PPPoE_SID]
jne .dump
 
mov ax, word [edx + PPPoE_frame.Payload]
add edx, PPPoE_frame.Payload + 2
 
cmp ax, PPP_IPv4
je IPv4_input
 
DEBUGF 2,"PPPoE_input: Unknown protocol=%x\n", ax
 
.dump:
DEBUGF 2,"PPPoE_input: dumping\n"
call kernel_free
add esp, 4
ret
 
 
 
 
;-----------------------------------------------------------------
;
; PPPoE discovery input
; PPPoE_output
;
; Handler of received Ethernet packet with type = Discovery
; IN:
; ebx = device ptr
; ecx = packet size
;
; di = protocol
;
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
; pointer to device struct in ebx
; pointer to PPP header in edx
; size of PPP packet in ecx
; OUT: /
; OUT: edi = 0 on error, pointer to buffer otherwise
; eax = buffer start
; ebx = to device structure
; ecx = unchanged (packet size of embedded data)
; edx = size of complete buffer
;
;-----------------------------------------------------------------
align 4
PPPoE_discovery_input:
PPPoE_output:
 
; 1. Minimum 6 bytes for PPPoE header.
cmp ecx, sizeof.PPPoE_header
jb .bad
DEBUGF 1,"PPPoE_output: size=%u device=%x\n", ecx, ebx
 
; 1. Ignore packets with ver<>1 and/or type<>1.
cmp [edx + PPPoE_header.VersionAndType], 0x11
jnz .bad
pushw di
pushw [PPPoE_SID]
 
; 2. Code must be either 7 for Offer,
; or 0x65 for Session-Confirmation, or 0xa7 for Terminate.
; Because only Initiation/Offers are supported, we expect only value 7.
cmp [edx + PPPoE_header.Code], 7
jnz .bad
lea eax, [ebx + ETH_DEVICE.mac]
lea edx, [PPPoE_MAC]
add ecx, PPPoE_frame.Payload + 2
mov di, ETHER_PPP_SESSION
call ETH_output
jz .eth_error
 
; 3. Session ID must be zero for Offers.
cmp [edx + PPPoE_header.SessionID], 0
jnz .bad
mov [edi + PPPoE_frame.VersionAndType], 0x11
mov [edi + PPPoE_frame.Code], 0
popw [edi + PPPoE_frame.SessionID]
xchg cl, ch
mov [edi + PPPoE_frame.Length], cx
xchg cl, ch
pop word [edi + PPPoE_frame.Payload]
 
; 4. Payload length
rol [edx + PPPoE_header.Length], 8 ; Convert INET byte order to intel
sub ecx, PPPoE_frame.Payload + 2
add edi, PPPoE_frame.Payload + 2
 
; 5. Ignore packet if nobody is listening.
cmp [PPPoE.cur_receiver], 0
jz .bad
DEBUGF 1,"PPPoE_output: success!\n"
ret
 
; 6. Good, now copy the received packet to the buffer of listener.
 
;;; TODO
.eth_error:
add esp, 4
xor edi, edi
 
.bad:
DEBUGF 1,'K : PPPoE - dumped\n'
call kernel_free
add esp, 4 ; pop (balance stack)
ret
 
 
 
align 4
PPPoE_start_connection:
 
cmp [PPPoE_SID], 0
je .fail
 
mov [PPPoE_SID], cx
mov dword [PPPoE_MAC], edx
mov word [PPPoE_MAC + 4], si
 
xor eax, eax
ret
 
.fail:
or eax, -1
ret
 
 
align 4
PPPoE_stop_connection:
 
xor eax, eax
mov [PPPoE_SID], ax
mov dword [PPPoE_MAC], eax
mov word [PPPoE_MAC + 4], ax
 
ret
 
 
;---------------------------------------------------------------------------
;
; PPPoE API
273,12 → 297,8
jmp dword [.table + 4*ebx]
 
.table:
dd PPPoE_send_init ; 0
dd PPPoE_stop_offers ; 1
dd PPPoE_alloc_connection ; 3
dd PPPoE_free_connection ; 4
dd PPPoE_send_discovery ; 5
dd PPPoE_receive_discovery ; 6
dd PPPoE_start_connection ; 0
dd PPPoE_stop_connection ; 1
.number = ($ - .table) / 4 - 1
 
.error:
/kernel/branches/net/network/ethernet.inc
80,11 → 80,11
; cmp ax, ETHER_IPv6
; je IPv6_input
 
; cmp ax, ETHER_PPP_DISCOVERY
; je PPPoE_discovery_input
cmp ax, ETHER_PPP_DISCOVERY
je PPPoE_discovery_input
 
; cmp ax, ETHER_PPP_SESSION
; je PPPoE_session_input
cmp ax, ETHER_PPP_SESSION
je PPPoE_session_input
 
DEBUGF 2,"ETH_input: Unknown packet type=%x\n", ax
 
/kernel/branches/net/network/socket.inc
299,6 → 299,13
je .raw
 
.no_inet4:
cmp ecx, AF_PPP
jne .no_ppp
 
cmp esi, PPP_PROTO_ETHERNET
je .pppoe
 
.no_ppp:
ret
 
align 4
347,8 → 354,17
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
ret
 
align 4
.pppoe:
push eax
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue
pop eax
 
mov [eax + SOCKET.snd_proc], SOCKET_send_pppoe
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
ret
 
 
;-----------------------------------------------------------------
;
; SOCKET_bind
872,8 → 888,23
ret
 
 
align 4
SOCKET_send_pppoe:
 
DEBUGF 1,"SOCKET_send: PPPoE\n"
 
mov [esp+32], ecx
mov ebx, [eax + SOCKET.device]
 
mov ecx, esi
call PPPoE_discovery_output
cmp eax, -1
je s_error
ret
 
 
 
 
;-----------------------------------------------------------------
;
; SOCKET_get_options
1126,7 → 1157,6
; Note: the mutex should already be set !
;
; IN: eax = socket ptr
; ebx = pointer to device struct
; ecx = data size
; esi = ptr to data
; [esp] = ptr to buf
/kernel/branches/net/network/stack.inc
43,11 → 43,15
ETHER_PPP_DISCOVERY = 0x6388
ETHER_PPP_SESSION = 0x6488
 
; PPP protocol numbers
PPP_IPv4 = 0x2100
 
;Protocol family
AF_UNSPEC = 0
AF_UNIX = 1
AF_INET4 = 2
AF_INET6 = 10
AF_PPP = 777
 
; Internet protocol numbers
IP_PROTO_IP = 0
55,6 → 59,9
IP_PROTO_TCP = 6
IP_PROTO_UDP = 17
 
; PPP protocol number
PPP_PROTO_ETHERNET = 666
 
; Socket types
SOCK_STREAM = 1
SOCK_DGRAM = 2
171,7 → 178,7
include "loopback.inc"
include "ethernet.inc"
 
;include "PPPoE.inc"
include "PPPoE.inc"
 
include "ARP.inc"
include "IPv4.inc"
714,8 → 721,8
cmp ax, API_ARP
je ARP_api
 
; cmp ax, API_PPPOE
; je PPPoE_api
cmp ax, API_PPPOE
je PPPoE_api
 
add esp, 4 ; if we reached here, no function was called, so we need to balance stack