Added PPPoE module.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5121 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
SubDir OBOS_TOP src add-ons kernel network ppp ;
|
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 ;
|
SubInclude OBOS_TOP src add-ons kernel network ppp shared ;
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Waldemar Kornewald, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Waldemar Kornewald, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -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 ;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Waldemar Kornewald, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -0,0 +1,443 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Waldemar Kornewald, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Waldemar Kornewald, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Waldemar Kornewald, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user