From 5a4503c3ff53541df235e97891a6e33af0c42cf1 Mon Sep 17 00:00:00 2001 From: Waldemar Kornewald Date: Thu, 23 Oct 2003 18:01:36 +0000 Subject: [PATCH] Added PPPoE module. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5121 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/network/ppp/Jamfile | 1 + .../network/ppp/pppoe/DiscoveryPacket.cpp | 152 ++++++ .../network/ppp/pppoe/DiscoveryPacket.h | 78 +++ src/add-ons/kernel/network/ppp/pppoe/Jamfile | 22 + src/add-ons/kernel/network/ppp/pppoe/PPPoE.h | 44 ++ .../kernel/network/ppp/pppoe/PPPoEDevice.cpp | 443 ++++++++++++++++++ .../kernel/network/ppp/pppoe/PPPoEDevice.h | 75 +++ .../kernel/network/ppp/pppoe/pppoe.cpp | 167 +++++++ 8 files changed, 982 insertions(+) create mode 100644 src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.cpp create mode 100644 src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.h create mode 100644 src/add-ons/kernel/network/ppp/pppoe/Jamfile create mode 100644 src/add-ons/kernel/network/ppp/pppoe/PPPoE.h create mode 100644 src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp create mode 100644 src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h create mode 100644 src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp diff --git a/src/add-ons/kernel/network/ppp/Jamfile b/src/add-ons/kernel/network/ppp/Jamfile index 63823aeaaf..0fbb7f7470 100644 --- a/src/add-ons/kernel/network/ppp/Jamfile +++ b/src/add-ons/kernel/network/ppp/Jamfile @@ -1,3 +1,4 @@ SubDir OBOS_TOP src add-ons kernel network ppp ; +SubInclude OBOS_TOP src add-ons kernel network ppp pppoe ; SubInclude OBOS_TOP src add-ons kernel network ppp shared ; diff --git a/src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.cpp b/src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.cpp new file mode 100644 index 0000000000..200b1442e9 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.cpp @@ -0,0 +1,152 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#include "DiscoveryPacket.h" + +#include +#include + + +DiscoveryPacket::DiscoveryPacket(uint8 code, uint16 sessionID = 0x0000) + : fCode(code), + fSessionID(sessionID) +{ +} + + +DiscoveryPacket::DiscoveryPacket(struct mbuf *packet) +{ + // decode packet + pppoe_header *header = mtod(packet, pppoe_header*); + + SetCode(header->code); + + if(ntohs(header->length) < 4) + return; + // there are no tags (or one corrupted tag) + + int32 position = 0; + pppoe_tag *tag; + + while(position <= ntohs(header->length) - 4) { + tag = (pppoe_tag*) (header->data + position); + position += ntohs(tag->length) + 4; + + AddTag(ntohs(tag->type), ntohs(tag->length), tag->data); + } +} + + +DiscoveryPacket::~DiscoveryPacket() +{ + for(int32 index = 0; index < CountTags(); index++) + free(TagAt(index)); +} + + +bool +DiscoveryPacket::AddTag(uint16 type, uint16 length, void *data, int32 index = -1) +{ + pppoe_tag *add = (pppoe_tag*) malloc(length + 4); + add->type = type; + add->length = length; + memcpy(add->data, data, length); + + bool status; + if(index < 0) + status = fTags.AddItem(add); + else + status = fTags.AddItem(add, index); + if(!status) { + free(add); + return false; + } + + return true; +} + + +bool +DiscoveryPacket::RemoveTag(pppoe_tag *tag) +{ + if(!fTags.HasItem(tag)) + return false; + + fTags.RemoveItem(tag); + free(tag); + + return true; +} + + +pppoe_tag* +DiscoveryPacket::TagAt(int32 index) const +{ + pppoe_tag *tag = fTags.ItemAt(index); + + if(tag == fTags.GetDefaultItem()) + return NULL; + + return tag; +} + + +pppoe_tag* +DiscoveryPacket::TagWithType(uint16 type) const +{ + pppoe_tag *tag; + + for(int32 index = 0; index < CountTags(); index++) { + tag = TagAt(index); + if(tag && tag->type == type) + return tag; + } + + return NULL; +} + + +struct mbuf* +DiscoveryPacket::ToMbuf(uint32 reserve = 0) +{ + struct mbuf *packet = m_gethdr(MT_DATA); + packet->m_data += reserve; + + pppoe_header *header = mtod(packet, pppoe_header*); + + memset(header, 0, sizeof(header)); + header->ethernetHeader.ether_type = ETHERTYPE_PPPOEDISC; + header->version = PPPoE_VERSION; + header->type = PPPoE_TYPE; + header->code = Code(); + header->sessionID = SessionID(); + + uint16 length = 0; + pppoe_tag *tag; + + for(int32 index = 0; index < CountTags(); index++) { + tag = TagAt(index); + + // make sure we have enough space left + if(1494 - length < tag->length) { + m_freem(packet); + return NULL; + } + + *((uint16*)(header->data + length)) = htons(tag->type); + length += 2; + *((uint16*)(header->data + length)) = htons(tag->length); + length += 2; + memcpy(header->data + length, tag->data, tag->length); + length += tag->length; + } + + header->length = htons(length); + packet->m_len = length; + + return packet; +} diff --git a/src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.h b/src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.h new file mode 100644 index 0000000000..54cf47a79c --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.h @@ -0,0 +1,78 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#ifndef DISCOVERY_PACKET__H +#define DISCOVERY_PACKET__H + +#include "PPPoE.h" + +#include + + +enum PPPoE_TAG_TYPE { + END_OF_LIST = 0x0000, + SERVICE_NAME = 0x0101, + AC_NAME = 0x0102, + HOST_UNIQ = 0x0103, + AC_COOKIE = 0x0104, + VENDOR_SPECIFIC = 0x0105, + RELAY_SESSION_ID = 0x0110, + SERVICE_NAME_ERROR = 0x0201, + AC_SYSTEM_ERROR = 0x0202, + GENERIC_ERROR = 0x0203 +}; + +enum PPPoE_CODE { + PADI = 0x09, + PADO = 0x07, + PADR = 0x19, + PADS = 0x65, + PADT = 0xA7 +}; + + +typedef struct pppoe_tag { + uint16 type; + uint16 length; + uint8 data[0]; +}; + + +class DiscoveryPacket { + public: + DiscoveryPacket(uint8 code, uint16 sessionID = 0x0000); + DiscoveryPacket(struct mbuf *packet); + ~DiscoveryPacket(); + + void SetCode(uint8 code) + { fCode = code; } + uint8 Code() const + { return fCode; } + + void SetSessionID(uint16 sessionID) + { fSessionID = sessionID; } + uint16 SessionID() const + { return fSessionID; } + + bool AddTag(uint16 type, uint16 length, void *data, int32 index = -1); + bool RemoveTag(pppoe_tag *tag); + int32 CountTags() const + { return fTags.CountItems(); } + pppoe_tag *TagAt(int32 index) const; + pppoe_tag *TagWithType(uint16 type) const; + + struct mbuf *ToMbuf(uint32 reserve = 0); + // the user is responsible for freeing the mbuf + + private: + uint8 fCode; + uint16 fSessionID; + List fTags; +}; + + +#endif diff --git a/src/add-ons/kernel/network/ppp/pppoe/Jamfile b/src/add-ons/kernel/network/ppp/pppoe/Jamfile new file mode 100644 index 0000000000..d834414da6 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pppoe/Jamfile @@ -0,0 +1,22 @@ +SubDir OBOS_TOP src add-ons kernel network ppp pppoe ; + +# for kernel_cpp.cpp/h and BLocker +UsePrivateHeaders net ; +UsePrivateHeaders [ FDirName kernel ] ; +UsePrivateHeaders [ FDirName kernel util ] ; +UseHeaders [ FDirName $(OBOS_TOP) src add-ons kernel network ppp shared libkernelppp headers ] ; +UseHeaders [ FDirName $(OBOS_TOP) src add-ons kernel network ppp shared libkernelppp ] ; + + +R5KernelAddon pppoe : kernel network ppp : + pppoe.cpp + PPPoEDevice.cpp + DiscoveryPacket.cpp +; + +LinkSharedOSLibs pppoe : libkernelppp.a ; + +# Installation +OBOSInstall install-networking + : /boot/home/config/add-ons/kernel/network/ppp + : pppoe ; diff --git a/src/add-ons/kernel/network/ppp/pppoe/PPPoE.h b/src/add-ons/kernel/network/ppp/pppoe/PPPoE.h new file mode 100644 index 0000000000..67ae601d09 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pppoe/PPPoE.h @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#ifndef PPPoE__H +#define PPPoE__H + +#include +#include +#include + + +#define PPPoE_HEADER_SIZE 14 + // including ethernet header +#define PPPoE_TIMEOUT 3000000 + // 3 seconds + +#define PPPoE_VERSION 0x1 +#define PPPoE_TYPE 0x1 + +#define PPPoE_INTERFACE_KEY "interface" + +extern struct core_module_info *core; + + +typedef struct pppoe_header { + struct ether_header ethernetHeader; + uint8 version : 4; + uint8 type : 4; + uint8 code; + uint16 sessionID; + uint16 length; + uint8 data[0]; +} pppoe_header _PACKED; + + +uint32 NewHostUniq(); + // defined in pppoe.cpp + + +#endif diff --git a/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp b/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp new file mode 100644 index 0000000000..146fe523f1 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp @@ -0,0 +1,443 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#include "PPPoEDevice.h" +#include "DiscoveryPacket.h" + +#include +#include +#include + +// from libkernelppp +#include +#include + +#ifdef _KERNEL_MODE + #define spawn_thread spawn_kernel_thread + #define printf dprintf +#endif + + +PPPoEDevice::PPPoEDevice(PPPInterface& interface, driver_parameter *settings) + : PPPDevice("PPPoE", interface, settings), + fEthernetIfnet(NULL), + fSessionID(0), + fHostUniq(NewHostUniq()), + fACName(NULL), + fServiceName(NULL), + fNextTimeout(0), + fState(INITIAL) +{ +#if DEBUG + printf("PPPoEDevice: Constructor\n"); + if(!settings || !settings->parameters) + printf("PPPoEDevice::ctor: No settings!\n"); + else if(settings->parameter_count > 0 && settings->parameters[0].value_count > 0) + printf("PPPoEDevice::ctor: Value0: %s\n", settings->parameters[0].values[0]); + else + printf("PPPoEDevice::ctor: No values!\n"); +#endif + + memset(fPeer, 0xFF, sizeof(fPeer)); + SetMTU(1494); + // MTU size does not contain PPP header + + // find ethernet device + const char *interfaceName = get_parameter_value(PPPoE_INTERFACE_KEY, settings); + if(!interfaceName) + return; +#if DEBUG + printf("PPPoEDevice::ctor: interfaceName: %s\n", interfaceName); +#endif + + ifnet *current = get_interfaces(); + for(; current; current = current->if_next) { + if(current->if_name && !strcmp(current->if_name, interfaceName)) { +#if DEBUG + printf("PPPoEDevice::ctor: found ethernet interface\n"); +#endif + fEthernetIfnet = current; + break; + } + } + +#if DEBUG + if(!fEthernetIfnet) + printf("PPPoEDevice::ctor: could not find ethernet interface\n"); +#endif +} + + +PPPoEDevice::~PPPoEDevice() +{ +#if DEBUG + printf("PPPoEDevice: Destructor\n"); +#endif + + free(fACName); + free(fServiceName); +} + + +status_t +PPPoEDevice::InitCheck() const +{ + return EthernetIfnet() && EthernetIfnet()->output + && PPPDevice::InitCheck() == B_OK ? B_OK : B_ERROR; +} + + +bool +PPPoEDevice::Up() +{ +#if DEBUG + printf("PPPoEDevice: Up()\n"); +#endif + + if(InitCheck() != B_OK) + return false; + + LockerHelper locker(fLock); + + if(IsUp()) + return true; + + // reset connection settings + memset(fPeer, 0xFF, sizeof(fPeer)); + + // create PADI + DiscoveryPacket discovery(PADI); + if(fServiceName) + discovery.AddTag(SERVICE_NAME, strlen(fServiceName), fServiceName); + else + discovery.AddTag(SERVICE_NAME, 0, NULL); + discovery.AddTag(HOST_UNIQ, sizeof(uint32), &fHostUniq); + discovery.AddTag(END_OF_LIST, 0, NULL); + + // set up PPP header + struct mbuf *packet = discovery.ToMbuf(); + if(!packet) + return false; + + // create destination + struct sockaddr destination; + memset(&destination, 0, sizeof(destination)); + destination.sa_family = AF_UNSPEC; + // raw packet with ethernet header + memcpy(destination.sa_data, fPeer, sizeof(fPeer)); + + if(EthernetIfnet()->output(EthernetIfnet(), packet, &destination, NULL) != B_OK) + return false; + + // check if we are allowed to go up now (user intervention might disallow that) + if(!UpStarted()) { + fState = INITIAL; + // reset state + DownEvent(); + return true; + } + + fState = PADI_SENT; + + fNextTimeout = system_time() + PPPoE_TIMEOUT; + + return true; +} + + +bool +PPPoEDevice::Down() +{ +#if DEBUG + printf("PPPoEDevice: Down()\n"); +#endif + + if(InitCheck() != B_OK) + return false; + + LockerHelper locker(fLock); + + fNextTimeout = 0; + // disable timeouts + + DownStarted(); + // this tells StateMachine that DownEvent() does not mean we lost connection + + if(!IsUp()) { + DownEvent(); + return true; + } + + // create PADT + DiscoveryPacket discovery(PADT, SessionID()); + discovery.AddTag(END_OF_LIST, 0, NULL); + + struct mbuf *packet = discovery.ToMbuf(); + if(!packet) { + DownEvent(); + return false; + } + + // create destination + struct sockaddr destination; + memset(&destination, 0, sizeof(destination)); + destination.sa_family = AF_UNSPEC; + // raw packet with ethernet header + memcpy(destination.sa_data, fPeer, sizeof(fPeer)); + + // reset connection settings + memset(fPeer, 0xFF, sizeof(fPeer)); + + EthernetIfnet()->output(EthernetIfnet(), packet, &destination, NULL); + DownEvent(); + + return false; +} + + +uint32 +PPPoEDevice::InputTransferRate() const +{ + return 10000000; +} + + +uint32 +PPPoEDevice::OutputTransferRate() const +{ + return 10000000; +} + + +uint32 +PPPoEDevice::CountOutputBytes() const +{ + // TODO: + // ?look through ethernet queue for outgoing pppoe packets coming from our device? + return 0; +} + + +status_t +PPPoEDevice::Send(struct mbuf *packet, uint16 protocolNumber = 0) +{ +#if DEBUG + printf("PPPoEDevice: Send()\n"); +#endif + + if(InitCheck() != B_OK || protocolNumber != 0) { + m_freem(packet); + return B_ERROR; + } else if(!packet) + return B_ERROR; + + LockerHelper locker(fLock); + + if(!IsUp()) + return PPP_NO_CONNECTION; + + uint16 length = packet->m_flags & M_PKTHDR ? packet->m_pkthdr.len : packet->m_len; + + // encapsulate packet into pppoe header + M_PREPEND(packet, PPPoE_HEADER_SIZE); + pppoe_header *header = mtod(packet, pppoe_header*); + header->ethernetHeader.ether_type = ETHERTYPE_PPPOE; + header->version = PPPoE_VERSION; + header->type = PPPoE_TYPE; + header->code = 0x00; + header->sessionID = SessionID(); + header->length = htons(length); + + // create destination + struct sockaddr destination; + memset(&destination, 0, sizeof(destination)); + destination.sa_family = AF_UNSPEC; + // raw packet with ethernet header + memcpy(destination.sa_data, fPeer, sizeof(fPeer)); + + locker.UnlockNow(); + + if(EthernetIfnet()->output(EthernetIfnet(), packet, &destination, NULL) != B_OK) { + printf("PPPoEDevice::Send(): EthernetIfnet()->output() failed!\n"); + DownEvent(); + // DownEvent() without DownStarted() indicates connection lost + return PPP_NO_CONNECTION; + } + + return B_OK; +} + + +status_t +PPPoEDevice::Receive(struct mbuf *packet, uint16 protocolNumber = 0) +{ +#if DEBUG + printf("PPPoEDevice: Receive()\n"); +#endif + + if(InitCheck() != B_OK || IsDown()) { + m_freem(packet); + return B_ERROR; + } else if(!packet) + return B_ERROR; + + pppoe_header *header = mtod(packet, pppoe_header*); + if(!header) { + m_freem(packet); + return B_ERROR; + } + + status_t result = B_OK; + + if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOE) { + if(!IsUp() || header->version != PPPoE_VERSION || header->type != PPPoE_TYPE + || header->code != 0x0 || header->sessionID != SessionID()) { + m_freem(packet); + return B_ERROR; + } + + m_adj(packet, PPPoE_HEADER_SIZE); + return Interface().ReceiveFromDevice(packet); + } else if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOEDISC) { + // we do not need to check HOST_UNIQ tag as this is done in pppoe.cpp + if(header->version != PPPoE_VERSION || header->type != PPPoE_TYPE) { + m_freem(packet); + return B_ERROR; + } + + LockerHelper locker(fLock); + + if(IsDown()) { + m_freem(packet); + return B_ERROR; + } + + DiscoveryPacket discovery(packet); + switch(discovery.Code()) { + case PADO: { + if(fState != PADI_SENT) { + m_freem(packet); + return B_OK; + } + + bool hasServiceName = false; + pppoe_tag *tag; + DiscoveryPacket reply(PADR); + for(int32 index = 0; index < discovery.CountTags(); index++) { + tag = discovery.TagAt(index); + switch(tag->type) { + case SERVICE_NAME: + if(!hasServiceName && (!fServiceName + || !memcmp(tag->data, fServiceName, tag->length))) { + hasServiceName = true; + reply.AddTag(tag->type, tag->length, tag->data); + } + break; + + case AC_COOKIE: + case RELAY_SESSION_ID: + reply.AddTag(tag->type, tag->length, tag->data); + break; + + case SERVICE_NAME_ERROR: + case AC_SYSTEM_ERROR: + case GENERIC_ERROR: + m_freem(packet); + return B_ERROR; + break; + + default: + ; + } + } + + if(!hasServiceName) { + m_freem(packet); + return B_ERROR; + } + + reply.AddTag(END_OF_LIST, 0, NULL); + struct mbuf *replyPacket = reply.ToMbuf(); + if(!replyPacket) { + m_freem(packet); + return B_ERROR; + } + + memcpy(fPeer, header->ethernetHeader.ether_shost, sizeof(fPeer)); + + // create destination + struct sockaddr destination; + memset(&destination, 0, sizeof(destination)); + destination.sa_family = AF_UNSPEC; + // raw packet with ethernet header + memcpy(destination.sa_data, fPeer, sizeof(fPeer)); + + if(EthernetIfnet()->output(EthernetIfnet(), replyPacket, &destination, + NULL) != B_OK) { + m_freem(packet); + return B_ERROR; + } + + fState = PADR_SENT; + fNextTimeout = system_time() + PPPoE_TIMEOUT; + } break; + + case PADS: + if(fState != PADR_SENT + || memcmp(header->ethernetHeader.ether_shost, fPeer, + sizeof(fPeer))) { + m_freem(packet); + return B_ERROR; + } + + fSessionID = header->sessionID; + fState = OPENED; + fNextTimeout = 0; + UpEvent(); + break; + + case PADT: + if(!IsUp() + || memcmp(header->ethernetHeader.ether_shost, fPeer, + sizeof(fPeer)) + || header->sessionID != SessionID()) { + m_freem(packet); + return B_ERROR; + } + + fState = INITIAL; + fSessionID = 0; + fNextTimeout = 0; + DownEvent(); + break; + + default: + m_freem(packet); + return B_ERROR; + } + } else + result = B_ERROR; + + m_freem(packet); + return result; +} + + +void +PPPoEDevice::Pulse() +{ + // We use Pulse() for timeout of connection establishment. + + if(fNextTimeout == 0 || IsUp() || IsDown()) + return; + + LockerHelper locker(fLock); + + // check if timed out + if(system_time() >= fNextTimeout) + Up(); +} diff --git a/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h b/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h new file mode 100644 index 0000000000..e0f85a9736 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#ifndef PPPoE_DEVICE__H +#define PPPoE_DEVICE__H + +#include "PPPoE.h" + +#include + + +enum pppoe_state { + INITIAL, + // the same as IsDown() + PADI_SENT, + PADR_SENT, + OPENED + // the same as IsUp() +}; + + +class PPPoEDevice : public PPPDevice { + public: + PPPoEDevice(PPPInterface& interface, driver_parameter *settings); + virtual ~PPPoEDevice(); + + ifnet *EthernetIfnet() const + { return fEthernetIfnet; } + + const uint8 *Peer() const + { return fPeer; } + uint16 SessionID() const + { return fSessionID; } + uint32 HostUniq() const + { return fHostUniq; } + + const char *ACName() const + { return fACName; } + const char *ServiceName() const + { return fServiceName; } + + virtual status_t InitCheck() const; + + virtual bool Up(); + virtual bool Down(); + + virtual uint32 InputTransferRate() const; + virtual uint32 OutputTransferRate() const; + + virtual uint32 CountOutputBytes() const; + + virtual status_t Send(struct mbuf *packet, uint16 protocolNumber = 0); + virtual status_t Receive(struct mbuf *packet, uint16 protocolNumber = 0); + + virtual void Pulse(); + + private: + ifnet *fEthernetIfnet; + uint8 fPeer[6]; + uint16 fSessionID; + uint32 fHostUniq; + char *fACName, *fServiceName; + + bigtime_t fNextTimeout; + pppoe_state fState; + + BLocker fLock; +}; + + +#endif diff --git a/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp b/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp new file mode 100644 index 0000000000..ccf1729c08 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp @@ -0,0 +1,167 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include "PPPoEDevice.h" +#include "DiscoveryPacket.h" + + +#ifdef _KERNEL_MODE + #define spawn_thread spawn_kernel_thread + #define printf dprintf +#endif + + +#define PPPoE_MODULE_NAME "network/ppp/pppoe" + +struct core_module_info *core = NULL; +static struct ethernet_module_info *ethernet; +static int32 host_uniq = 0; +status_t std_ops(int32 op, ...); + +static BLocker lock; +static List devices; + + +uint32 +NewHostUniq() +{ + return (uint32) atomic_add(&host_uniq, 1); +} + + +static +void +pppoe_input(struct mbuf *packet) +{ + if(!packet) + return; + + ifnet *sourceIfnet = packet->m_pkthdr.rcvif; + pppoe_header *header = mtod(packet, pppoe_header*); + PPPoEDevice *device; + + LockerHelper locker(lock); + + for(int32 index = 0; index < devices.CountItems(); index++) { + device = devices.ItemAt(index); + + if(device && device->EthernetIfnet() == sourceIfnet) { + if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOE + && header->sessionID == device->SessionID()) { + device->Receive(packet); + return; + } else if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOE + && header->code != PADI && header->code != PADR + && !device->IsDown()) { + DiscoveryPacket discovery(packet); + pppoe_tag *tag = discovery.TagWithType(HOST_UNIQ); + if(tag && tag->length == 4 + && *((uint32*)tag->data) == device->HostUniq()) { + device->Receive(packet); + return; + } + } + } + } + + printf("PPPoE: No device found for packet from: %s\n", sourceIfnet->if_name); + m_freem(packet); +} + + +static +bool +add_to(PPPInterface& mainInterface, PPPInterface *subInterface, + driver_parameter *settings, ppp_module_key_type type) +{ + if(type != PPP_DEVICE_KEY_TYPE) + return B_ERROR; + + PPPoEDevice *device; + bool success; + if(subInterface) { + device = new PPPoEDevice(*subInterface, settings); + success = subInterface->SetDevice(device); + } else + device = new PPPoEDevice(mainInterface, settings); { + success = mainInterface.SetDevice(device); + } + +#if DEBUG + printf("PPPoE: add_to(): %s\n", success && device && device->InitCheck() == B_OK ? "OK" : "ERROR"); +#endif + + return success && device && device->InitCheck() == B_OK; +} + + +static ppp_module_info pppoe_module = { + { + PPPoE_MODULE_NAME, + 0, + std_ops + }, + NULL, + add_to +}; + + +_EXPORT +status_t +std_ops(int32 op, ...) +{ + switch(op) { + case B_MODULE_INIT: + if(get_module(NET_CORE_MODULE_NAME, (module_info**)&core) != B_OK) + return B_ERROR; + + if(get_module(NET_ETHERNET_MODULE_NAME, (module_info**)ðernet) != B_OK) { + put_module(NET_CORE_MODULE_NAME); + return B_ERROR; + } + + ethernet->set_pppoe_receiver(pppoe_input); + +#if DEBUG + printf("PPPoE: Registered PPPoE receiver.\n"); +#endif + return B_OK; + + case B_MODULE_UNINIT: + ethernet->unset_pppoe_receiver(); +#if DEBUG + printf("PPPoE: Unregistered PPPoE receiver.\n"); +#endif + put_module(NET_CORE_MODULE_NAME); + put_module(NET_ETHERNET_MODULE_NAME); + break; + + default: + return B_ERROR; + } + + return B_OK; +} + + +_EXPORT +module_info *modules[] = { + (module_info*) &pppoe_module, + NULL +};