From de28332c4d4286165bd819da5c2a7e9fe1995cf1 Mon Sep 17 00:00:00 2001 From: hidnplayr Date: Sun, 19 Aug 2012 19:09:09 +0000 Subject: [PATCH] Rewrote PPPoE from scratch. TODO: link IPv4_output to PPPoE_session_output git-svn-id: svn://kolibrios.org@2931 a494cfbc-eb01-0410-851d-a64ba20cac60 --- kernel/branches/net/network/PPPoE.inc | 428 ++++++++++++----------- kernel/branches/net/network/ethernet.inc | 8 +- kernel/branches/net/network/socket.inc | 32 +- kernel/branches/net/network/stack.inc | 13 +- 4 files changed, 269 insertions(+), 212 deletions(-) diff --git a/kernel/branches/net/network/PPPoE.inc b/kernel/branches/net/network/PPPoE.inc index d76f970ed9..684a738d6e 100644 --- a/kernel/branches/net/network/PPPoE.inc +++ b/kernel/branches/net/network/PPPoE.inc @@ -1,197 +1,38 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; -;; 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_header +struct PPPoE_frame 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 - - pid dd ? ; identifier of base application - - 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 ? + + PPPoE_SID dw ? + PPPoE_MAC dp ? + endg -; Allocates internal structure for future PPPoE actions. -align 4 -PPPoE_alloc_connection: - -; 1. Allocate memory in the kernel area. - stdcall kernel_alloc, sizeof.PPPoE_connection - -; 1a. If memory allocation failed, return NULL. - test eax, eax - jz .nothing - -; 2. Copy PID of caller to the structure. - mov edx, [CURRENT_TASK] - mov [eax + PPPoE_connection.pid], edx - -; 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 - - .nothing: - ret - - -align 4 -PPPoE_free_connection: - -; 1. Check that the caller is the owner of this connection. - mov eax, [CURRENT_TASK] - cmp [ebx+PPPoE_connection.pid], eax - jnz .nothing - -; 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 - -; 3. Free the memory. - stdcall kernel_free, ebx - - .nothing: - 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 -align 4 -PPPoE_send_init: - -; 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 - ja .bad - -; 2. Check that no one listen for offers. - cmp [PPPoE.cur_receiver], 0 - jnz .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 - -; 4. Create packet. - test ecx, ecx - jnz @f - mov esi, .default_payload - mov ecx, .default_payload_length - @@: - - 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 - - push edx eax - -; 4b. Set ver=1, type=1 (=> first byte 0x11), code=9 (PADI packet), session=0 - mov dword [edi], (0x09 shl 8) + 0x11 - -; 4c. Set payload length. - mov [edi+4], ch - mov [edi+5], cl - -; 4e. Copy given tags. - rep movsb - -; 5. Send packet. - call [ebx + NET_DEVICE.transmit] -; 6. Return. - xor eax, eax - ret - - .bad: - or eax, -1 - ret - - .default_payload: -; Service-Name tag with zero length - dw 0x0101, 0x0000 - .default_payload_length = $ - .default_payload - - -; Stop receiving PADO packets -align 4 -PPPoE_stop_offers: - -; 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 - - .bad: - or eax, -1 - ret - -; Send PPPoE data in Discovery stage -align 4 -PPPoE_send_discovery: - ret - -; Receive PPPoE data in Discovery stage -align 4 -PPPoE_receive_discovery: - ret - - - ;----------------------------------------------------------------- ; ; PPPoE discovery input @@ -210,42 +51,225 @@ PPPoE_receive_discovery: align 4 PPPoE_discovery_input: -; 1. Minimum 6 bytes for PPPoE header. - cmp ecx, sizeof.PPPoE_header - jb .bad + DEBUGF 2,"PPPoE_discovery_input\n" -; 1. Ignore packets with ver<>1 and/or type<>1. - cmp [edx + PPPoE_header.VersionAndType], 0x11 - jnz .bad +; First, find open PPPoE socket -; 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 + mov eax, net_sockets -; 3. Session ID must be zero for Offers. - cmp [edx + PPPoE_header.SessionID], 0 - jnz .bad + .next_socket: + mov eax, [eax + SOCKET.NextPtr] + or eax, eax + jz .dump -; 4. Payload length - rol [edx + PPPoE_header.Length], 8 ; Convert INET byte order to intel + cmp [eax + SOCKET.Domain], AF_PPP + jne .next_socket -; 5. Ignore packet if nobody is listening. - cmp [PPPoE.cur_receiver], 0 - jz .bad + cmp [eax + SOCKET.Protocol], PPP_PROTO_ETHERNET + jne .next_socket -; 6. Good, now copy the received packet to the buffer of listener. +; Now, send it to the this socket - ;;; TODO + mov ecx, [esp + 4] + mov esi, [esp] - .bad: - DEBUGF 1,'K : PPPoE - dumped\n' + jmp SOCKET_input + + .dump: + DEBUGF 1,'PPPoE_discovery_input: dumping\n' call kernel_free - add esp, 4 ; pop (balance stack) + add esp, 4 ret +;-------------------------------------- +; +; Send discovery packet +; +; ebx (ecx in app) = device +; ecx (edx in app) = size packet +; edx (esi in app) = pointer to packet +; +;-------------------------------------- +align 4 +PPPoE_discovery_output: + +; RFC2516: An entire PADI packet (including the PPPoE header) MUST NOT +; exceed 1484 octets. + cmp ecx, 1484 + 14 + ja .bad + +; Check that device exists and is ethernet device + cmp ebx, MAX_NET_DEVICES + ja .bad + + mov ebx, [NET_DRV_LIST + 4*ebx] + test ebx, ebx + jz .bad + + cmp [ebx + NET_DEVICE.type], NET_TYPE_ETH + jne .bad + +; Create packet. + stdcall kernel_alloc, 1500 + test eax, eax + jz .bad + + push ecx eax + + mov edi, eax + rep movsb + +; 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 + +; And send the packet + call [ebx + NET_DEVICE.transmit] + + xor eax, eax + ret + + .bad: + or eax, -1 + ret + + +;----------------------------------------------------------------- +; +; 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_session_input: + + cmp [edx + PPPoE_frame.VersionAndType], 0x11 + jne .dump + + cmp [edx + PPPoE_frame.Code], 0x00 + jne .dump + + movzx ecx, [edx + PPPoE_frame.Length] + xchg cl, ch + + 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_output +; +; IN: +; ebx = device ptr +; ecx = packet size +; +; di = protocol +; +; 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_output: + + DEBUGF 1,"PPPoE_output: size=%u device=%x\n", ecx, ebx + + pushw di + pushw [PPPoE_SID] + + 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 + + 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] + + sub ecx, PPPoE_frame.Payload + 2 + add edi, PPPoE_frame.Payload + 2 + + DEBUGF 1,"PPPoE_output: success!\n" + ret + + + .eth_error: + add esp, 4 + xor edi, edi + + 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 ;--------------------------------------------------------------------------- @@ -273,12 +297,8 @@ PPPoE_api: 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: diff --git a/kernel/branches/net/network/ethernet.inc b/kernel/branches/net/network/ethernet.inc index 9602e04b16..6eab9b55e0 100644 --- a/kernel/branches/net/network/ethernet.inc +++ b/kernel/branches/net/network/ethernet.inc @@ -80,11 +80,11 @@ ETH_input: ; 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 diff --git a/kernel/branches/net/network/socket.inc b/kernel/branches/net/network/socket.inc index 79edae7edb..1ae7d0140f 100644 --- a/kernel/branches/net/network/socket.inc +++ b/kernel/branches/net/network/socket.inc @@ -299,6 +299,13 @@ SOCKET_open: je .raw .no_inet4: + cmp ecx, AF_PPP + jne .no_ppp + + cmp esi, PPP_PROTO_ETHERNET + je .pppoe + + .no_ppp: ret align 4 @@ -347,6 +354,15 @@ align 4 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 ;----------------------------------------------------------------- @@ -872,6 +888,21 @@ SOCKET_send_icmp: 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 + + ;----------------------------------------------------------------- @@ -1126,7 +1157,6 @@ SOCKET_check_port: ; 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 diff --git a/kernel/branches/net/network/stack.inc b/kernel/branches/net/network/stack.inc index cd30c5098c..ad5de50143 100644 --- a/kernel/branches/net/network/stack.inc +++ b/kernel/branches/net/network/stack.inc @@ -43,11 +43,15 @@ ETHER_IPv6 = 0xDD86 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_ICMP = 1 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 "queue.inc" include "loopback.inc" include "ethernet.inc" -;include "PPPoE.inc" +include "PPPoE.inc" include "ARP.inc" include "IPv4.inc" @@ -714,8 +721,8 @@ sys_protocols: 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