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: |