Added PPPoE module.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5121 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
4fbbad3009
commit
5a4503c3ff
@ -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 ;
|
||||
|
152
src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.cpp
Normal file
152
src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.cpp
Normal file
@ -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 <core_funcs.h>
|
||||
#include <kernel_cpp.h>
|
||||
|
||||
|
||||
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;
|
||||
}
|
78
src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.h
Normal file
78
src/add-ons/kernel/network/ppp/pppoe/DiscoveryPacket.h
Normal file
@ -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 <List.h>
|
||||
|
||||
|
||||
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<pppoe_tag*> fTags;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
22
src/add-ons/kernel/network/ppp/pppoe/Jamfile
Normal file
22
src/add-ons/kernel/network/ppp/pppoe/Jamfile
Normal file
@ -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 ;
|
44
src/add-ons/kernel/network/ppp/pppoe/PPPoE.h
Normal file
44
src/add-ons/kernel/network/ppp/pppoe/PPPoE.h
Normal file
@ -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 <SupportDefs.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
|
||||
#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
|
443
src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp
Normal file
443
src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp
Normal file
@ -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 <core_funcs.h>
|
||||
#include <cstdlib>
|
||||
#include <kernel_cpp.h>
|
||||
|
||||
// from libkernelppp
|
||||
#include <settings_tools.h>
|
||||
#include <LockerHelper.h>
|
||||
|
||||
#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();
|
||||
}
|
75
src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h
Normal file
75
src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h
Normal file
@ -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 <KPPPDevice.h>
|
||||
|
||||
|
||||
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
|
167
src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp
Normal file
167
src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp
Normal file
@ -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 <core_funcs.h>
|
||||
#include <KernelExport.h>
|
||||
#include <driver_settings.h>
|
||||
|
||||
#include <kernel_cpp.h>
|
||||
|
||||
#include <ethernet_module.h>
|
||||
|
||||
#include <KPPPInterface.h>
|
||||
#include <KPPPModule.h>
|
||||
#include <LockerHelper.h>
|
||||
|
||||
#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<PPPoEDevice*> 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
|
||||
};
|
Loading…
Reference in New Issue
Block a user