Finished first set of needed features (tests will follow as soon as the needed kernel modules are available).

Next step will be to add:
- Protocol-Field-Compression support (including PFC handler)
- MRU option handler
- ?simple authentication option handler (helper class)?


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4513 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Waldemar Kornewald 2003-09-06 01:00:12 +00:00
parent 8d1a0ee7c1
commit a602502a7e
22 changed files with 757 additions and 365 deletions

View File

@ -45,6 +45,8 @@ class PPPConfigurePacket {
int32 CountItems() const
{ return fItems.CountItems(); }
ppp_configure_item *ItemAt(int32 index) const;
bool HasItemWithType(uint8 type) const;
ppp_configure_item *ItemWithType(uint8 type) const;
struct mbuf *ToMbuf(uint32 reserve = 0);
// the user is responsible for freeing the mbuf

View File

@ -18,8 +18,9 @@ typedef uint32 interface_id;
// module key types (used when loading a module)
enum {
PPP_LOAD_MODULE_TYPE,
enum PPP_MODULE_KEY_TYPE {
PPP_UNDEFINED_KEY_TYPE = -1,
PPP_LOAD_MODULE_TYPE = 0,
PPP_DEVICE_TYPE,
PPP_PROTOCOL_TYPE,
PPP_AUTHENTICATOR_TYPE,

View File

@ -19,7 +19,7 @@
class PPPDevice {
public:
PPPDevice(const char *name, uint32 overhead, PPPInterface *interface,
PPPDevice(const char *name, PPPInterface& interface,
driver_parameter *settings);
virtual ~PPPDevice();
@ -28,10 +28,7 @@ class PPPDevice {
const char *Name() const
{ return fName; }
uint32 Overhead() const
{ return fOverhead; }
PPPInterface *Interface() const
PPPInterface& Interface() const
{ return fInterface; }
driver_parameter *Settings() const
{ return fSettings; }
@ -85,8 +82,7 @@ class PPPDevice {
private:
char fName[PPP_HANDLER_NAME_LENGTH_LIMIT + 1];
uint32 fOverhead;
PPPInterface *fInterface;
PPPInterface& fInterface;
driver_parameter *fSettings;
uint32 fMTU;

View File

@ -24,7 +24,7 @@ class PPPEncapsulator {
PPPEncapsulator(const char *name, PPP_PHASE phase,
PPP_ENCAPSULATION_LEVEL level, uint16 protocol,
int32 addressFamily, uint32 overhead,
PPPInterface *interface, driver_parameter *settings,
PPPInterface& interface, driver_parameter *settings,
int32 flags = PPP_NO_FLAGS);
virtual ~PPPEncapsulator();
@ -41,7 +41,7 @@ class PPPEncapsulator {
uint32 Overhead() const
{ return fOverhead; }
PPPInterface *Interface() const
PPPInterface& Interface() const
{ return fInterface; }
driver_parameter *Settings() const
{ return fSettings; }
@ -58,8 +58,6 @@ class PPPEncapsulator {
bool IsEnabled() const
{ return fEnabled; }
void SetUpRequested(bool requested = true)
{ fUpRequested = requested; }
bool IsUpRequested() const
{ return fUpRequested; }
@ -92,6 +90,9 @@ class PPPEncapsulator {
virtual void Pulse();
protected:
void SetUpRequested(bool requested = true)
{ fUpRequested = requested; }
void UpStarted();
void DownStarted();
@ -109,7 +110,7 @@ class PPPEncapsulator {
PPP_ENCAPSULATION_LEVEL fLevel;
uint16 fProtocol;
int32 fAddressFamily;
PPPInterface *fInterface;
PPPInterface& fInterface;
driver_parameter *fSettings;
int32 fFlags;

View File

@ -74,12 +74,13 @@ class PPPInterface {
bigtime_t DisconnectAfterIdleSince() const
{ return fDisconnectAfterIdleSince; }
void SetLinkMTU(uint32 linkMTU);
uint32 LinkMTU() const
{ return fLinkMTU; }
// this is the smallest MTU that we and the peer have
void SetMRU(uint32 MRU);
uint32 MRU() const
{ return fMRU; }
// this is the smallest MRU that we and the peer have
uint32 InterfaceMTU() const
{ return fInterfaceMTU; }
// this is the MRU including encapsulator overhead
status_t Control(uint32 op, void *data, size_t length);
@ -92,12 +93,14 @@ class PPPInterface {
int32 CountProtocols() const
{ return fProtocols.CountItems(); }
PPPProtocol *ProtocolAt(int32 index) const;
PPPProtocol *ProtocolFor(uint16 protocol, int32 start = 0) const;
PPPProtocol *ProtocolFor(uint16 protocol, int32 *start = NULL) const;
int32 IndexOfProtocol(PPPProtocol *protocol) const
{ return fProtocols.IndexOf(protocol); }
bool AddEncapsulator(PPPEncapsulator *encapsulator);
bool RemoveEncapsulator(PPPEncapsulator *encapsulator);
int32 CountEncapsulators() const;
PPPEncapsulator *EncapsulatorAt(int32 index) const;
PPPEncapsulator *FirstEncapsulator() const
{ return fFirstEncapsulator; }
PPPEncapsulator *EncapsulatorFor(uint16 protocol,
@ -144,7 +147,7 @@ class PPPInterface {
bool LoadModules(driver_settings *settings,
int32 start, int32 count);
bool LoadModule(const char *name, driver_parameter *parameter,
int32 type);
PPP_MODULE_KEY_TYPE type);
status_t Send(struct mbuf *packet, uint16 protocol);
status_t Receive(struct mbuf *packet, uint16 protocol);
@ -164,7 +167,7 @@ class PPPInterface {
// saves the returned ifnet structure
bool UnregisterInterface();
void CalculateMRU();
void CalculateInterfaceMTU();
void CalculateBaudRate();
void Redial();
@ -191,7 +194,7 @@ class PPPInterface {
ppp_manager_info *fManager;
bigtime_t fIdleSince, fDisconnectAfterIdleSince;
uint32 fLinkMTU, fMRU, fHeaderLength;
uint32 fMRU, fInterfaceMTU, fHeaderLength;
PPPInterface *fParent;
List<PPPInterface*> fChildren;
@ -211,6 +214,7 @@ class PPPInterface {
BLocker& fLock;
status_t fInitStatus;
int32 fDeleteCounter;
};

View File

@ -28,6 +28,7 @@ typedef struct ppp_manager_info {
// you should always create interfaces using this function
void (*delete_interface)(interface_id ID);
// this marks the interface for deletion
void (*remove_interface)(interface_id ID);
ifnet* (*register_interface)(interface_id ID);
bool (*unregister_interface)(interface_id ID);

View File

@ -16,11 +16,12 @@ class PPPInterface;
typedef struct ppp_module_info {
module_info minfo;
status_t (*control)(uint32 op, void *data, size_t length);
status_t (*add_to)(PPPInterface *mainInterface, PPPInterface *subInterface,
driver_parameter *settings, int32 type);
status_t (*add_to)(PPPInterface& mainInterface, PPPInterface *subInterface,
driver_parameter *settings, PPP_MODULE_KEY_TYPE type);
// multilink: handlers that must run on a real device
// should be added to subInterface while mainInterface
// handlers are used for the bundle of interfaces
// should be added to subInterface (may be NULL)
// while mainInterface handlers are used for the
// bundle of interfaces
} ppp_module_info;

View File

@ -21,23 +21,25 @@ class PPPConfigurePacket;
class PPPOptionHandler {
public:
PPPOptionHandler(const char *name, PPPInterface *interface,
PPPOptionHandler(const char *name, PPPInterface& interface,
driver_parameter *settings);
virtual ~PPPOptionHandler();
virtual status_t InitCheck() const;
const char *Name() const
{ return fName; }
PPPInterface& Interface() const
{ return fInterface; }
driver_parameter *Settings() const
{ return fSettings; }
void SetEnabled(bool enabled = true);
bool IsEnabled() const
{ return fEnabled; }
const char *Name() const
{ return fName; }
PPPInterface *Interface() const
{ return fInterface; }
driver_parameter *Settings() const
{ return fSettings; }
virtual status_t Control(uint32 op, void *data, size_t length);
virtual void Reset() = 0;
// e.g.: remove list of rejected values
@ -61,7 +63,7 @@ class PPPOptionHandler {
private:
char fName[PPP_HANDLER_NAME_LENGTH_LIMIT + 1];
PPPInterface *fInterface;
PPPInterface& fInterface;
driver_parameter *fSettings;
bool fEnabled;

View File

@ -18,7 +18,7 @@ class PPPInterface;
class PPPProtocol {
public:
PPPProtocol(const char *name, PPP_PHASE phase, uint16 protocol,
int32 addressFamily, PPPInterface *interface,
int32 addressFamily, PPPInterface& interface,
driver_parameter *settings, int32 flags = PPP_NO_FLAGS);
virtual ~PPPProtocol();
@ -30,7 +30,7 @@ class PPPProtocol {
PPP_PHASE Phase() const
{ return fPhase; }
PPPInterface *Interface() const
PPPInterface& Interface() const
{ return fInterface; }
driver_parameter *Settings() const
{ return fSettings; }
@ -47,8 +47,6 @@ class PPPProtocol {
bool IsEnabled() const
{ return fEnabled; }
void SetUpRequested(bool requested = true)
{ fUpRequested = requested; }
bool IsUpRequested() const
{ return fUpRequested; }
@ -71,6 +69,9 @@ class PPPProtocol {
virtual void Pulse();
protected:
void SetUpRequested(bool requested = true)
{ fUpRequested = requested; }
void UpStarted();
void DownStarted();
@ -84,7 +85,7 @@ class PPPProtocol {
PPP_PHASE fPhase;
uint16 fProtocol;
int32 fAddressFamily;
PPPInterface *fInterface;
PPPInterface& fInterface;
driver_parameter *fSettings;
int32 fFlags;

View File

@ -8,6 +8,29 @@
#ifndef _K_PPP_UTILS__H
#define _K_PPP_UTILS__H
#ifndef _K_PPP_DEFS__H
#include <KPPPDefs.h>
#endif
// helper functions
template<class T>
inline
bool
is_handler_allowed(T& handler, PPP_STATE state, PPP_PHASE phase)
{
if(handler.Protocol() == PPP_LCP_PROTOCOL)
return true;
else if(state != PPP_OPENED_STATE)
return false;
else if(phase > PPP_AUTHENTICATION_PHASE
|| (phase >= PPP_ESTABLISHMENT_PHASE
&& handler.Flags() & PPP_ALWAYS_ALLOWED))
return true;
else
return false;
}
// These are very simple send/receive_data functions with a timeout
// and there is a race condition beween has_data() and send/receive_data().

View File

@ -31,7 +31,7 @@ class LockerHelper {
public:
LockerHelper(BLocker& lock) : fLock(&lock)
{
if(fLock->Lock() != B_OK)
if(!fLock->Lock())
fLock = NULL;
}

View File

@ -15,32 +15,27 @@
// starting values and other values for control ops
#define PPP_RESERVE_OPS_COUNT 0xFFFF
#define PPP_OPS_START B_DEVICE_OP_CODES_END + 1
#define PPP_INTERFACE_OPS_START PPP_OPS_START + PPP_RESERVE_OPS_COUNT
#define PPP_DEVICE_OPS_START PPP_OPS_START + 2 * PPP_RESERVE_OPS_COUNT
#define PPP_PROTOCOL_OPS_START PPP_OPS_START + 3 * PPP_RESERVE_OPS_COUNT
#define PPP_ENCAPSULATOR_OPS_START PPP_OPS_START + 4 * PPP_RESERVE_OPS_COUNT
#define PPP_OPTION_HANDLER_OPS_START PPP_OPS_START + 5 * PPP_RESERVE_OPS_COUNT
#define PPP_LCP_EXTENSION_OPS_START PPP_OPS_START + 6 * PPP_RESERVE_OPS_COUNT
#define PPP_COMMON_PROTO_ENCAPS_OPS_START PPP_OPS_START + 10 * PPP_RESERVE_OPS_COUNT
#define PPP_COMMON_OPS_START PPP_OPS_START + 10 * PPP_RESERVE_OPS_COUNT
#define PPP_COMMON_PROTO_ENCAPS_OPS_START PPP_OPS_START + 11 * PPP_RESERVE_OPS_COUNT
#define PPP_USER_OPS_START PPP_OPS_START + 32 * PPP_RESERVE_OPS_COUNT
enum PPP_CONTROL_OPS {
// -----------------------------------------------------
// PPPInterface
PPPC_GET_STATUS = PPP_OPS_START,
PPPC_GET_MRU,
PPPC_GET_INTERFACE_INFO = PPP_INTERFACE_OPS_START,
PPPC_SET_MRU,
PPPC_GET_LINK_MTU,
PPPC_SET_LINK_MTU,
PPPC_GET_DIAL_ON_DEMAND,
PPPC_SET_DIAL_ON_DEMAND,
PPPC_GET_AUTO_REDIAL,
PPPC_SET_AUTO_REDIAL,
PPPC_GET_PROTOCOLS_COUNT,
PPPC_GET_ENCAPSULATORS_COUNT,
PPPC_GET_OPTION_HANDLERS_COUNT,
PPPC_GET_LCP_EXTENSIONS_COUNT,
PPPC_GET_CHILDREN_COUNT,
// handler access
PPPC_CONTROL_DEVICE,
PPPC_CONTROL_PROTOCOL,
PPPC_CONTROL_ENCAPSULATOR,
PPPC_CONTROL_OPTION_HANDLER,
@ -50,9 +45,8 @@ enum PPP_CONTROL_OPS {
// -----------------------------------------------------
// PPPDevice
PPPC_GET_MTU = PPP_DEVICE_OPS_START,
PPPC_GET_DEVICE_INFO = PPP_DEVICE_OPS_START,
PPPC_SET_MTU,
PPPC_GET_PREFERRED_MTU,
// -----------------------------------------------------
// -----------------------------------------------------
@ -65,6 +59,7 @@ enum PPP_CONTROL_OPS {
// -----------------------------------------------------
// PPPOptionHandler
PPPC_GET_OPTION_HANDLER_INFO = PPP_OPTION_HANDLER_OPS_START,
// -----------------------------------------------------
// -----------------------------------------------------
@ -72,45 +67,116 @@ enum PPP_CONTROL_OPS {
// -----------------------------------------------------
// -----------------------------------------------------
// PPPProtocol and PPPEncapsulator
PPPC_GET_NAME,
PPPC_GET_ENABLED = PPP_COMMON_PROTO_ENCAPS_OPS_START,
// Common/mixed ops
PPPC_GET_HANDLER_INFO = PPP_COMMON_OPS_START,
PPPC_SET_ENABLED,
// -----------------------------------------------------
// -----------------------------------------------------
// PPPProtocol and PPPEncapsulator
// -----------------------------------------------------
PPP_CONTROL_OPS_END = B_DEVICE_OP_CODES_END + 0xFFFF
};
typedef struct ppp_control_structure {
typedef struct ppp_control_info {
uint32 index;
// index of interface/protocol/encapsulator/etc.
uint32 op;
// the Control()/ioctl() opcode
union {
void *data;
ppp_control_struct *subcontrol;
} pointer;
// either a pointer to the data or a pointer to a control structure for
// accessing protocols/encapsulators/etc.
void *data;
size_t length;
// not always needed
} ppp_control_structure;
// should always be set
} ppp_control_info;
typedef struct ppp_status_structure {
// -----------------------------------------------------------
// structures for storing information about interface/handlers
// use the xxx_info_t structures when allocating memory (they
// reserve memory for future implementations)
// -----------------------------------------------------------
#define _PPP_INFO_T_SIZE_ 256
typedef struct ppp_interface_info {
const driver_settings *settings;
PPP_MODE mode;
PPP_STATE state;
PPP_PHASE phase;
PPP_AUTHENTICATION_STATUS authenticationStatus, peerAuthenticationStatus;
bigtime_t idle_since;
uint32 protocolsCount, encapsulatorsCount, optionHandlersCount,
LCPExtensionsCount, childrenCount;
uint32 MRU, interfaceMTU;
uint8 _reserved_[64 - (sizeof(PPP_MODE) + sizeof(PPP_STATE) + sizeof(PPP_PHASE)
+ 2 * sizeof(PPP_AUTHENTICATION_STATUS) + sizeof(bigtime_t))];
} ppp_status_structure;
bigtime_t idleSince, disconnectAfterIdleSince;
bool doesDialOnDemand, doesAutoRedial, hasDevice, isMultilink, hasParent;
} ppp_interface_info;
typedef struct ppp_interface_info_t {
ppp_interface_info info;
uint8 _reserved_[_PPP_INFO_T_SIZE_ - sizeof(ppp_interface_info)];
} ppp_interface_info_t;
// devices are special handlers, so they have their own structure
typedef struct ppp_device_info {
char name[PPP_HANDLER_NAME_LENGTH_LIMIT + 1];
const driver_parameter *settings;
uint32 MTU, preferredMTU;
uint32 inputTransferRate, outputTransferRate, outputBytesCount;
} ppp_device_info;
typedef struct ppp_device_info_t {
ppp_device_info info;
uint8 _reserved_[_PPP_INFO_T_SIZE_ - sizeof(ppp_device_info)];
} ppp_device_info_t;
typedef struct ppp_handler_info {
char name[PPP_HANDLER_NAME_LENGTH_LIMIT + 1];
// general
const driver_parameter *settings;
PPP_PHASE phase;
int32 addressFamily, flags;
uint16 protocol;
bool isEnabled;
// only protocol and encapsulator
bool isUpRequested;
PPP_PHASE connectionStatus;
// there are four possible states:
// PPP_ESTABLISHED_PHASE - IsUp() == true
// PPP_DOWN_PHASE - IsDown() == true
// PPP_ESTABLISHMENT_PHASE - IsGoingUp() == true
// PPP_TERMINATION_PHASE - IsGoingDown() == true
// only encapsulator
PPP_ENCAPSULATION_LEVEL level;
uint32 overhead;
} ppp_handler_info;
typedef struct ppp_handler_info_t {
ppp_handler_info info;
uint8 _reserved_[_PPP_INFO_T_SIZE_ - sizeof(ppp_handler_info)];
} ppp_handler_info_t;
typedef struct ppp_option_handler_info {
char name[PPP_HANDLER_NAME_LENGTH_LIMIT + 1];
const driver_parameter *settings;
bool isEnabled;
} ppp_option_handler_info;
typedef struct ppp_option_handler_info_t {
ppp_option_handler_info info;
uint8 _reserved_[_PPP_INFO_T_SIZE_ - sizeof(ppp_option_handler_info)];
} ppp_option_handler_info_t;
#endif

View File

@ -12,7 +12,7 @@
// various constants
#define PPP_HANDLER_NAME_LENGTH_LIMIT 255
#define PPP_HANDLER_NAME_LENGTH_LIMIT 63
// if the name is longer than this value it will be truncated
// settings keys
@ -66,13 +66,17 @@ enum {
enum {
PPP_NO_FLAGS = 0x00,
PPP_ALWAYS_ALLOWED = 0x01,
// protocol may send/receive in PPP_ESTABLISHMENT_PHASE
// protocol may send/receive in Phase() >= PPP_ESTABLISHMENT_PHASE,
// but only LCP is allowed in State() != PPP_OPENED_STATE!
PPP_NEEDS_DOWN = 0x02,
// protocol needs a Down() in addition to a Reset() to
// terminate the connection properly (losing the connection
// still results in a Reset() only)
PPP_NOT_IMPORTANT = 0x03
PPP_NOT_IMPORTANT = 0x04,
// if this protocol fails to go up we do not disconnect
PPP_INCLUDES_NCP = 0x08
// This protocol includes the corresponding NCP protocol (e.g.: IPCP + IP).
// All protocol values will also be checked against Protocol() & 0x7FFF.
};
// phase when the protocol is brought up

View File

@ -25,11 +25,11 @@ enum PPP_REPORT_FLAGS {
};
// report types
// the first 16 report types are reserved for the interface manager
enum PPP_REPORT_TYPE {
PPP_DESTRUCTION_REPORT = 0,
PPP_DESTRUCTION_REPORT = 16,
// the interface is being destroyed (no code is needed)
PPP_CONNECTION_REPORT = 1,
PPP_AUTHENTICATION_REPORT = 2
PPP_CONNECTION_REPORT = 17
};
// report codes (type-specific)

View File

@ -107,6 +107,36 @@ PPPConfigurePacket::ItemAt(int32 index) const
}
bool
PPPConfigurePacket::HasItemWithType(uint8 type) const
{
ppp_configure_item *item;
for(int32 index; index < CountItems(); index++) {
item = ItemAt(index);
if(item && item->type == type)
return true;
}
return false;
}
ppp_configure_item*
PPPConfigurePacket::ItemWithType(uint8 type) const
{
ppp_configure_item *item;
for(int32 index; index < CountItems(); index++) {
item = ItemAt(index);
if(item && item->type == type)
return item;
}
return NULL;
}
struct mbuf*
PPPConfigurePacket::ToMbuf(uint32 reserve = 0)
{

View File

@ -10,36 +10,33 @@
#include <net/if.h>
#include <mbuf.h>
#include <PPPControl.h>
PPPDevice::PPPDevice(const char *name, uint32 overhead, PPPInterface *interface,
PPPDevice::PPPDevice(const char *name, PPPInterface& interface,
driver_parameter *settings)
: fOverhead(overhead), fInterface(interface),
fSettings(settings)
: fInterface(interface), fSettings(settings), fMTU(1500)
{
if(name) {
strncpy(fName, name, PPP_HANDLER_NAME_LENGTH_LIMIT);
fName[PPP_HANDLER_NAME_LENGTH_LIMIT] = 0;
} else
strcpy(fName, "");
strcpy(fName, "???");
SetMTU(1500);
if(interface)
interface->SetDevice(this);
interface.SetDevice(this);
}
PPPDevice::~PPPDevice()
{
if(Interface())
Interface()->SetDevice(NULL);
Interface().SetDevice(NULL);
}
status_t
PPPDevice::InitCheck() const
{
if(!Interface() || !Settings())
if(!Settings())
return B_ERROR;
return B_OK;
@ -50,37 +47,43 @@ status_t
PPPDevice::Control(uint32 op, void *data, size_t length)
{
switch(op) {
// TODO:
// get:
// - name
// - mtu (+ preferred)
// - status
// - transfer rates
case PPPC_GET_DEVICE_INFO: {
if(length < sizeof(ppp_device_info_t) || !data)
return B_NO_MEMORY;
ppp_device_info *info = (ppp_device_info*) data;
memset(info, 0, sizeof(ppp_device_info_t));
strcpy(info->name, Name());
info->settings = Settings();
info->MTU = MTU();
info->preferredMTU = PreferredMTU();
info->inputTransferRate = InputTransferRate();
info->outputTransferRate = OutputTransferRate();
info->outputBytesCount = CountOutputBytes();
} break;
case PPPC_SET_MTU:
if(length < sizeof(uint32) || !data)
return B_ERROR;
return SetMTU(*((uint32*)data)) ? B_OK : B_ERROR;
break;
default:
return B_ERROR;
return PPP_UNHANDLED;
}
return B_OK;
}
bool
PPPDevice::SetMTU(uint32 MTU)
{
fMTU = MTU;
return true;
}
status_t
PPPDevice::PassToInterface(struct mbuf *packet)
{
if(!Interface() || !Interface()->InQueue())
if(!Interface().InQueue())
return B_ERROR;
IFQ_ENQUEUE(Interface()->InQueue(), packet);
IFQ_ENQUEUE(Interface().InQueue(), packet);
return B_OK;
}
@ -96,20 +99,14 @@ PPPDevice::Pulse()
bool
PPPDevice::UpStarted() const
{
if(!Interface())
return false;
return Interface()->StateMachine().TLSNotify();
return Interface().StateMachine().TLSNotify();
}
bool
PPPDevice::DownStarted() const
{
if(!Interface())
return false;
return Interface()->StateMachine().TLFNotify();
return Interface().StateMachine().TLFNotify();
}
@ -118,10 +115,7 @@ PPPDevice::UpFailedEvent()
{
fIsUp = false;
if(!Interface())
return;
Interface()->StateMachine().UpFailedEvent();
Interface().StateMachine().UpFailedEvent();
}
@ -130,10 +124,7 @@ PPPDevice::UpEvent()
{
fIsUp = true;
if(!Interface())
return;
Interface()->StateMachine().UpEvent();
Interface().StateMachine().UpEvent();
}
@ -142,8 +133,5 @@ PPPDevice::DownEvent()
{
fIsUp = false;
if(!Interface())
return;
Interface()->StateMachine().DownEvent();
Interface().StateMachine().DownEvent();
}

View File

@ -6,12 +6,15 @@
//---------------------------------------------------------------------
#include <KPPPEncapsulator.h>
#include <KPPPUtils.h>
#include <PPPControl.h>
PPPEncapsulator::PPPEncapsulator(const char *name, PPP_PHASE phase,
PPP_ENCAPSULATION_LEVEL level, uint16 protocol,
int32 addressFamily, uint32 overhead,
PPPInterface *interface, driver_parameter *settings,
PPPInterface& interface, driver_parameter *settings,
int32 flags = PPP_NO_FLAGS)
: fOverhead(overhead), fPhase(phase), fLevel(level), fProtocol(protocol),
fAddressFamily(addressFamily), fInterface(interface),
@ -22,24 +25,22 @@ PPPEncapsulator::PPPEncapsulator(const char *name, PPP_PHASE phase,
strncpy(fName, name, PPP_HANDLER_NAME_LENGTH_LIMIT);
fName[PPP_HANDLER_NAME_LENGTH_LIMIT] = 0;
} else
strcpy(fName, "");
strcpy(fName, "???");
if(interface)
interface->AddEncapsulator(this);
interface.AddEncapsulator(this);
}
PPPEncapsulator::~PPPEncapsulator()
{
if(Interface())
Interface()->RemoveEncapsulator(this);
Interface().RemoveEncapsulator(this);
}
status_t
PPPEncapsulator::InitCheck() const
{
if(!Interface() || !Settings())
if(!Settings())
return B_ERROR;
return B_OK;
@ -51,13 +52,10 @@ PPPEncapsulator::SetEnabled(bool enabled = true)
{
fEnabled = enabled;
if(!Interface())
return;
if(!enabled) {
if(IsUp() || IsGoingUp())
Down();
} else if(!IsUp() && !IsGoingUp() && IsUpRequested() && Interface()->IsUp())
} else if(!IsUp() && !IsGoingUp() && IsUpRequested() && Interface().IsUp())
Up();
}
@ -66,16 +64,34 @@ status_t
PPPEncapsulator::Control(uint32 op, void *data, size_t length)
{
switch(op) {
// TODO:
// get:
// - name
// - level, protocol, address family, overhead
// - status (Is(Going)Up/Down/UpRequested/Enabled)
// set:
// - enabled
case PPPC_GET_HANDLER_INFO: {
if(length < sizeof(ppp_handler_info_t) || !data)
return B_ERROR;
ppp_handler_info *info = (ppp_handler_info*) data;
memset(info, 0, sizeof(ppp_handler_info_t));
strcpy(info->name, Name());
info->settings = Settings();
info->phase = Phase();
info->addressFamily = AddressFamily();
info->flags = Flags();
info->protocol = Protocol();
info->isEnabled = IsEnabled();
info->isUpRequested = IsUpRequested();
info->connectionStatus = fConnectionStatus;
info->level = Level();
info->overhead = Overhead();
} break;
case PPPC_SET_ENABLED:
if(length < sizeof(uint32) || !data)
return B_ERROR;
SetEnabled(*((uint32*)data));
break;
default:
return B_ERROR;
return PPP_UNHANDLED;
}
return B_OK;
@ -85,12 +101,18 @@ PPPEncapsulator::Control(uint32 op, void *data, size_t length)
status_t
PPPEncapsulator::SendToNext(struct mbuf *packet, uint16 protocol) const
{
if(Next())
return Next()->Send(packet, protocol);
else if(Interface())
return Interface()->SendToDevice(packet, protocol);
else
return B_ERROR;
// Find the next possible handler for this packet.
// This handler should be:
// - enabled
// - allowed to send
if(Next()) {
if(Next()->IsEnabled()
&& is_handler_allowed(*Next(), Interface().State(), Interface().Phase()))
return Next()->Send(packet, protocol);
else
return Next()->SendToNext(packet, protocol);
} else
return Interface().SendToDevice(packet, protocol);
}
@ -120,10 +142,7 @@ PPPEncapsulator::UpFailedEvent()
{
fConnectionStatus = PPP_DOWN_PHASE;
if(!Interface())
return;
Interface()->StateMachine().UpFailedEvent(this);
Interface().StateMachine().UpFailedEvent(this);
}
@ -132,10 +151,7 @@ PPPEncapsulator::UpEvent()
{
fConnectionStatus = PPP_ESTABLISHED_PHASE;
if(!Interface())
return;
Interface()->StateMachine().UpEvent(this);
Interface().StateMachine().UpEvent(this);
}
@ -144,8 +160,5 @@ PPPEncapsulator::DownEvent()
{
fConnectionStatus = PPP_DOWN_PHASE;
if(!Interface())
return;
Interface()->StateMachine().DownEvent(this);
Interface().StateMachine().DownEvent(this);
}

View File

@ -5,7 +5,7 @@
// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de
//---------------------------------------------------------------------
// Stdio.h must be included before PPPModule.h/PPPManager.h because
// stdio.h must be included before PPPModule.h/PPPManager.h because
// dprintf is defined twice with different return values, once with
// void (KernelExport.h) and once with int (stdio.h).
#include <cstdio>
@ -16,8 +16,10 @@
#include <KPPPInterface.h>
// our other classes
#include <PPPControl.h>
#include <KPPPDevice.h>
#include <KPPPEncapsulator.h>
#include <KPPPOptionHandler.h>
#include <KPPPModule.h>
#include <KPPPManager.h>
#include <KPPPUtils.h>
@ -40,10 +42,11 @@ typedef struct redial_info {
thread_id *thread;
} redial_info;
status_t redial_func(void *data);
status_t redial_thread(void *data);
// other functions
status_t in_queue_thread(void *data);
status_t interface_deleter_thread(void *data);
PPPInterface::PPPInterface(uint32 ID, driver_settings *settings,
@ -51,12 +54,12 @@ PPPInterface::PPPInterface(uint32 ID, driver_settings *settings,
: fID(ID), fSettings(dup_driver_settings(settings)),
fStateMachine(*this), fLCP(*this), fReportManager(StateMachine().Locker()),
fIfnet(NULL), fUpThread(-1), fRedialThread(-1), fDialRetry(0),
fDialRetriesLimit(0), fIdleSince(0), fLinkMTU(1500), fDevice(NULL),
fFirstEncapsulator(NULL), fLock(StateMachine().Locker())
fDialRetriesLimit(0), fIdleSince(0), fMRU(1500), fDevice(NULL),
fFirstEncapsulator(NULL), fLock(StateMachine().Locker()), fDeleteCounter(0)
{
// set up queue
fInQueue = start_ifq();
fInQueueThread = spawn_thread(in_queue_thread, "PPPInterface: Input",
fInQueueThread = spawn_thread(in_queue_thread, "PPPInterface: in_queue_thread",
B_NORMAL_PRIORITY, this);
resume_thread(fInQueueThread);
@ -124,9 +127,23 @@ PPPInterface::PPPInterface(uint32 ID, driver_settings *settings,
PPPInterface::~PPPInterface()
{
if(fLock.Lock() != B_OK)
return;;
// make sure no thread wants to call Unlock() on fLock after it is deleted
++fDeleteCounter;
// make sure we are not accessible by any thread before we continue
UnregisterInterface();
if(fManager)
fManager->remove_interface(ID());
// Call Down() until we get a lock on an interface that is down.
// This lock is not released until we are actually deleted.
while(true) {
Down();
fLock.Lock();
if(State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE)
break;
fLock.Unlock();
}
Report(PPP_DESTRUCTION_REPORT, 0, NULL, 0);
// tell all listeners that we are being destroyed
@ -135,13 +152,10 @@ PPPInterface::~PPPInterface()
stop_ifq(InQueue());
wait_for_thread(fInQueueThread, &tmp);
Down();
UnregisterInterface();
wait_for_thread(fRedialThread, &tmp);
while(CountChildren())
ChildAt(0)->Delete();
delete ChildAt(0);
delete Device();
@ -156,16 +170,34 @@ PPPInterface::~PPPInterface()
free(fModules.ItemAt(index));
}
put_module(PPP_MANAGER_MODULE_NAME);
free_driver_settings(fSettings);
if(Parent())
Parent()->RemoveChild(this);
if(fManager)
put_module(PPP_MANAGER_MODULE_NAME);
}
void
PPPInterface::Delete()
{
fManager->delete_interface(ID());
if(atomic_add(&fDeleteCounter, 1) > 0)
return;
// only one thread should delete us!
if(fManager)
fManager->delete_interface(ID());
// This will mark us for deletion.
// Any subsequent calls to delete_interface() will do nothing.
else {
// We were not created by the manager.
// Spawn a thread that will delete us.
thread_id interfaceDeleterThread = spawn_thread(interface_deleter_thread,
"PPPInterface: interface_deleter_thread", B_NORMAL_PRIORITY, this);
resume_thread(interfaceDeleterThread);
}
}
@ -187,13 +219,13 @@ PPPInterface::InitCheck() const
void
PPPInterface::SetLinkMTU(uint32 linkMTU)
PPPInterface::SetMRU(uint32 MRU)
{
LockerHelper locker(fLock);
fLinkMTU = linkMTU;
fMRU = MRU;
CalculateMRU();
CalculateInterfaceMTU();
}
@ -201,16 +233,124 @@ status_t
PPPInterface::Control(uint32 op, void *data, size_t length)
{
switch(op) {
// TODO:
// add:
// - routing Control() to encapsulators/protocols/option_handlers
// (calling their Control() method)
// - adding modules
// - setting AutoRedial and DialOnDemand
case PPPC_GET_INTERFACE_INFO: {
if(length < sizeof(ppp_interface_info_t) || !data)
return B_NO_MEMORY;
ppp_interface_info *info = (ppp_interface_info*) data;
memset(info, 0, sizeof(ppp_interface_info_t));
info->settings = Settings();
info->mode = Mode();
info->state = State();
info->phase = Phase();
info->authenticationStatus = StateMachine().AuthenticationStatus();
info->peerAuthenticationStatus =
StateMachine().PeerAuthenticationStatus();
info->protocolsCount = CountProtocols();
info->encapsulatorsCount = CountEncapsulators();
info->optionHandlersCount = LCP().CountOptionHandlers();
info->LCPExtensionsCount = 0;
info->childrenCount = CountChildren();
info->MRU = MRU();
info->interfaceMTU = InterfaceMTU();
info->idleSince = IdleSince();
info->disconnectAfterIdleSince = DisconnectAfterIdleSince();
info->doesDialOnDemand = DoesDialOnDemand();
info->doesAutoRedial = DoesAutoRedial();
info->hasDevice = Device();
info->isMultilink = IsMultilink();
info->hasParent = Parent();
} break;
case PPPC_SET_MRU:
if(length < sizeof(uint32) || !data)
return B_ERROR;
SetMRU(*((uint32*)data));
break;
case PPPC_SET_DIAL_ON_DEMAND:
if(length < sizeof(uint32) || !data)
return B_NO_MEMORY;
SetDialOnDemand(*((uint32*)data));
break;
case PPPC_SET_AUTO_REDIAL:
if(length < sizeof(uint32) || !data)
return B_NO_MEMORY;
SetAutoRedial(*((uint32*)data));
break;
case PPPC_CONTROL_DEVICE: {
if(length < sizeof(ppp_control_info) || !data)
return B_ERROR;
ppp_control_info *control = (ppp_control_info*) data;
if(control->index != 0 || !Device())
return B_BAD_INDEX;
return Device()->Control(control->op, control->data, control->length);
} break;
case PPPC_CONTROL_PROTOCOL: {
if(length < sizeof(ppp_control_info) || !data)
return B_ERROR;
ppp_control_info *control = (ppp_control_info*) data;
PPPProtocol *protocol_handler = ProtocolAt(control->index);
if(!protocol_handler)
return B_BAD_INDEX;
return protocol_handler->Control(control->op, control->data,
control->length);
} break;
case PPPC_CONTROL_ENCAPSULATOR: {
if(length < sizeof(ppp_control_info) || !data)
return B_ERROR;
ppp_control_info *control = (ppp_control_info*) data;
PPPEncapsulator *encapsulator_handler = EncapsulatorAt(control->index);
if(!encapsulator_handler)
return B_BAD_INDEX;
return encapsulator_handler->Control(control->op, control->data,
control->length);
} break;
case PPPC_CONTROL_OPTION_HANDLER: {
if(length < sizeof(ppp_control_info) || !data)
return B_ERROR;
ppp_control_info *control = (ppp_control_info*) data;
PPPOptionHandler *option_handler = LCP().OptionHandlerAt(control->index);
if(!option_handler)
return B_BAD_INDEX;
return option_handler->Control(control->op, control->data,
control->length);
} break;
case PPPC_CONTROL_LCP_EXTENSION: {
return PPP_UNHANDLED;
} break;
case PPPC_CONTROL_CHILD: {
if(length < sizeof(ppp_control_info) || !data)
return B_ERROR;
ppp_control_info *control = (ppp_control_info*) data;
PPPInterface *child = ChildAt(control->index);
if(!child)
return B_BAD_INDEX;
return child->Control(control->op, control->data, control->length);
} break;
default:
return B_ERROR;
return PPP_UNHANDLED;
}
return B_OK;
@ -238,9 +378,9 @@ PPPInterface::SetDevice(PPPDevice *device)
fDevice = device;
fLinkMTU = fDevice->MTU();
fMRU = fDevice->MTU();
CalculateMRU();
CalculateInterfaceMTU();
CalculateBaudRate();
return true;
@ -300,14 +440,28 @@ PPPInterface::ProtocolAt(int32 index) const
PPPProtocol*
PPPInterface::ProtocolFor(uint16 protocol, int32 start = 0) const
PPPInterface::ProtocolFor(uint16 protocol, int32 *start = NULL) const
{
if(start < 0)
// The iteration style in this method is strange C/C++.
// Explanation: I use this style because it makes extending ProtocolFor
// and EncapsulatorFor simpler as that they look very similar, now.
int32 index = start ? *start : 0;
if(index < 0)
return NULL;
for(int32 i = start; i < fProtocols.CountItems(); i++)
if(fProtocols.ItemAt(i)->Protocol() == protocol)
return fProtocols.ItemAt(i);
PPPProtocol *current = ProtocolAt(index);
for(; current; current = ProtocolAt(++index)) {
if(current->Protocol() == protocol
|| (current->Flags() & PPP_INCLUDES_NCP
&& current->Protocol() & 0x7FFF == protocol & 0x7FFF)) {
if(start)
*start = index;
return current;
}
}
return NULL;
}
@ -354,7 +508,7 @@ PPPInterface::AddEncapsulator(PPPEncapsulator *encapsulator)
previous->SetNext(encapsulator);
}
CalculateMRU();
CalculateInterfaceMTU();
if(IsUp())
encapsulator->Up();
@ -386,7 +540,7 @@ PPPInterface::RemoveEncapsulator(PPPEncapsulator *encapsulator)
current->SetNext(NULL);
CalculateMRU();
CalculateInterfaceMTU();
return true;
}
@ -399,15 +553,42 @@ PPPInterface::RemoveEncapsulator(PPPEncapsulator *encapsulator)
}
int32
PPPInterface::CountEncapsulators() const
{
PPPEncapsulator *encapsulator = FirstEncapsulator();
int32 count = 0;
for(; encapsulator; encapsulator = encapsulator->Next())
++count;
return count;
}
PPPEncapsulator*
PPPInterface::EncapsulatorFor(uint16 protocol,
PPPEncapsulator *start = NULL) const
PPPInterface::EncapsulatorAt(int32 index) const
{
PPPEncapsulator *encapsulator = FirstEncapsulator();
int32 currentIndex = 0;
for(; encapsulator; encapsulator = encapsulator->Next(), ++currentIndex)
if(currentIndex == index)
return encapsulator;
return NULL;
}
PPPEncapsulator*
PPPInterface::EncapsulatorFor(uint16 protocol, PPPEncapsulator *start = NULL) const
{
PPPEncapsulator *current = start ? start : fFirstEncapsulator;
for(; current; current = current->Next())
if(current->Protocol() == protocol)
for(; current; current = current->Next()) {
if(current->Protocol() == protocol
|| (current->Flags() & PPP_INCLUDES_NCP
&& current->Protocol() & 0x7FFF == protocol & 0x7FFF))
return current;
}
return current;
}
@ -442,7 +623,7 @@ PPPInterface::RemoveChild(PPPInterface *child)
// parents cannot exist without their children
if(CountChildren() == 0 && fManager && Ifnet())
fManager->delete_interface(ID());
Delete();
return true;
}
@ -495,7 +676,7 @@ PPPInterface::SetDialOnDemand(bool dialondemand = true)
bool
PPPInterface::Up()
{
if(!InitCheck() || Phase() == PPP_TERMINATION_PHASE)
if(InitCheck() != B_OK || Phase() == PPP_TERMINATION_PHASE)
return false;
if(IsUp())
@ -504,8 +685,11 @@ PPPInterface::Up()
ppp_report_packet report;
thread_id me = find_thread(NULL), sender;
// one thread has to do the real task while all other threads are observers
fLock.Lock();
// One thread has to do the real task while all other threads are observers.
// Lock needs timeout because destructor could have locked the interface.
while(!fLock.LockWithTimeout(100000) != B_NO_ERROR)
if(fDeleteCounter > 0)
return false;
if(fUpThread == -1)
fUpThread = me;
@ -518,15 +702,19 @@ PPPInterface::Up()
while(true) {
if(IsUp()) {
ReportManager().DisableReports(PPP_CONNECTION_REPORT, me);
// lock needs timeout because destructor could have locked the interface
while(!fLock.LockWithTimeout(100000) != B_NO_ERROR)
if(fDeleteCounter > 0)
return true;
if(me == fUpThread) {
fLock.Lock();
fDialRetry = 0;
fUpThread = -1;
fLock.Unlock();
}
ReportManager().DisableReports(PPP_CONNECTION_REPORT, me);
fLock.Unlock();
return true;
}
@ -578,7 +766,7 @@ PPPInterface::Up()
fUpThread = -1;
if(!DoesDialOnDemand() && report.code != PPP_REPORT_DOWN_SUCCESSFUL)
fManager->delete_interface(ID());
Delete();
}
PPP_REPLY(sender, B_OK);
@ -616,7 +804,7 @@ PPPInterface::Up()
if(!DoesDialOnDemand()
&& report.code != PPP_REPORT_DOWN_SUCCESSFUL)
fManager->delete_interface(ID());
Delete();
PPP_REPLY(sender, B_OK);
ReportManager().DisableReports(PPP_CONNECTION_REPORT, me);
@ -643,7 +831,7 @@ PPPInterface::Up()
if(!DoesDialOnDemand()
&& report.code != PPP_REPORT_DOWN_SUCCESSFUL)
fManager->delete_interface(ID());
Delete();
return false;
}
@ -661,7 +849,7 @@ PPPInterface::Up()
bool
PPPInterface::Down()
{
if(!InitCheck())
if(InitCheck() != B_OK)
return false;
// this locked section guarantees that there are no state changes before we
@ -682,6 +870,12 @@ PPPInterface::Down()
if(receive_data(&sender, &report, sizeof(report)) != PPP_REPORT_CODE)
continue;
if(report.type == PPP_DESTRUCTION_REPORT)
return true;
if(report.type != PPP_CONNECTION_REPORT)
continue;
if(report.code == PPP_REPORT_DOWN_SUCCESSFUL
|| report.code == PPP_REPORT_UP_ABORTED
|| (State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE)) {
@ -691,7 +885,7 @@ PPPInterface::Down()
}
if(!DoesDialOnDemand())
fManager->delete_interface(ID());
Delete();
return true;
}
@ -713,18 +907,18 @@ PPPInterface::LoadModules(driver_settings *settings, int32 start, int32 count)
return false;
// a running connection may not change
int32 type;
PPP_MODULE_KEY_TYPE type;
// which type key was used for loading this module?
const char *name = NULL;
// multilink handling
for(int32 i = start;
i < settings->parameter_count && i < start + count; i++) {
if(!strcasecmp(settings->parameters[i].name, PPP_MULTILINK_KEY)
&& settings->parameters[i].value_count > 0) {
if(!LoadModule(settings->parameters[i].values[0],
settings->parameters[i].parameters, PPP_MULTILINK_TYPE))
for(int32 index = start;
index < settings->parameter_count && index < start + count; index++) {
if(!strcasecmp(settings->parameters[index].name, PPP_MULTILINK_KEY)
&& settings->parameters[index].value_count > 0) {
if(!LoadModule(settings->parameters[index].values[0],
settings->parameters[index].parameters, PPP_MULTILINK_TYPE))
return false;
break;
}
@ -739,11 +933,11 @@ PPPInterface::LoadModules(driver_settings *settings, int32 start, int32 count)
return true;
}
for(int32 i = start;
i < settings->parameter_count && i < start + count; i++) {
type = -1;
for(int32 index = start;
index < settings->parameter_count && index < start + count; index++) {
type = PPP_UNDEFINED_KEY_TYPE;
name = settings->parameters[i].name;
name = settings->parameters[index].name;
if(!strcasecmp(name, PPP_LOAD_MODULE_KEY))
type = PPP_LOAD_MODULE_TYPE;
@ -757,10 +951,10 @@ PPPInterface::LoadModules(driver_settings *settings, int32 start, int32 count)
type = PPP_PEER_AUTHENTICATOR_TYPE;
if(type >= 0)
for(int32 value_id = 0; value_id < settings->parameters[i].value_count;
for(int32 value_id = 0; value_id < settings->parameters[index].value_count;
value_id++)
if(!LoadModule(settings->parameters[i].values[value_id],
settings->parameters[i].parameters, type))
if(!LoadModule(settings->parameters[index].values[value_id],
settings->parameters[index].parameters, type))
return false;
}
@ -770,7 +964,7 @@ PPPInterface::LoadModules(driver_settings *settings, int32 start, int32 count)
bool
PPPInterface::LoadModule(const char *name, driver_parameter *parameter,
int32 type)
PPP_MODULE_KEY_TYPE type)
{
if(Phase() != PPP_DOWN_PHASE)
return false;
@ -791,7 +985,7 @@ PPPInterface::LoadModule(const char *name, driver_parameter *parameter,
// for putting them on our destruction
fModules.AddItem(module_name);
return module->add_to(Parent()?Parent():this, this, parameter, type);
return module->add_to(Parent()?*Parent():*this, this, parameter, type);
}
@ -817,16 +1011,37 @@ PPPInterface::Send(struct mbuf *packet, uint16 protocol)
if(DoesDialOnDemand() && Phase() == PPP_DOWN_PHASE)
Up();
// If this protocol is always allowed we should send the packet.
// Note that these protocols are not passed to encapsulators!
PPPProtocol *sending_protocol = ProtocolFor(protocol);
// find the protocol handler for the current protocol number
int32 index = 0;
PPPProtocol *sending_protocol = ProtocolFor(protocol, &index);
while(sending_protocol && !sending_protocol->IsEnabled())
sending_protocol = ProtocolFor(protocol, &(++index));
// Check if we must encapsulate the packet.
// We do not necessarily need a handler for 'protocol'.
// In such a case we still encapsulate the packet.
// Protocols which have the PPP_ALWAYS_ALLOWED flag set are never
// encapsulated.
if(sending_protocol && sending_protocol->Flags() & PPP_ALWAYS_ALLOWED
&& sending_protocol->IsEnabled() && fDevice->IsUp()) {
&& is_handler_allowed(*sending_protocol, State(), Phase())) {
fIdleSince = system_time();
return SendToDevice(packet, protocol);
}
// never send normal protocols when we are down
// try the same for the encapsulator handler
PPPEncapsulator *sending_encapsulator = EncapsulatorFor(protocol);
while(sending_encapsulator && sending_encapsulator->Next()
&& !sending_encapsulator->IsEnabled())
sending_encapsulator = sending_encapsulator->Next() ?
EncapsulatorFor(protocol, sending_encapsulator->Next()) : NULL;
if(sending_encapsulator && sending_encapsulator->Flags() & PPP_ALWAYS_ALLOWED
&& is_handler_allowed(*sending_encapsulator, State(), Phase())) {
fIdleSince = system_time();
return SendToDevice(packet, protocol);
}
// never send normal protocols when we are not up
if(!IsUp()) {
m_freem(packet);
return B_ERROR;
@ -841,7 +1056,11 @@ PPPInterface::Send(struct mbuf *packet, uint16 protocol)
if(!fFirstEncapsulator->IsEnabled())
return fFirstEncapsulator->SendToNext(packet, protocol);
return fFirstEncapsulator->Send(packet, protocol);
if(is_handler_allowed(*fFirstEncapsulator, State(), Phase()))
return fFirstEncapsulator->Send(packet, protocol);
m_freem(packet);
return B_ERROR;
}
@ -854,43 +1073,42 @@ PPPInterface::Receive(struct mbuf *packet, uint16 protocol)
int32 result = PPP_REJECTED;
// assume we have no handler
// Set our interface as the receiver.
// The real netstack protocols (IP, IPX, etc.) might get confused if our
// interface is a main interface and at the same time is not registered
// because then there is no receiver interface.
// PPP NCPs should be aware of that!
if(packet->m_flags & M_PKTHDR && Ifnet() != NULL)
packet->m_pkthdr.rcvif = Ifnet();
// Find handler and let it parse the packet.
// The handler does need not be up because if we are a server
// the handler might be upped by this packet.
PPPEncapsulator *encapsulator_handler = EncapsulatorFor(protocol);
for(; encapsulator_handler;
encapsulator_handler = EncapsulatorFor(protocol, encapsulator_handler->Next())) {
if(!encapsulator_handler->IsEnabled()) {
if(!encapsulator_handler->Next())
break;
encapsulator_handler =
encapsulator_handler->Next() ?
EncapsulatorFor(protocol, encapsulator_handler->Next()) : NULL) {
if(!encapsulator_handler->IsEnabled()
|| !is_handler_allowed(*encapsulator_handler, State(), Phase()))
continue;
// disabled handlers should not be used
}
// skip handler if disabled or not allowed
result = encapsulator_handler->Receive(packet, protocol);
if(result == PPP_UNHANDLED) {
if(!encapsulator_handler->Next())
break;
if(result == PPP_UNHANDLED)
continue;
}
return result;
}
// no encapsulator handler could be found; try a protocol handler
PPPProtocol *protocol_handler;
for(int32 index = 0; index < CountProtocols(); index++) {
protocol_handler = ProtocolAt(index);
if(protocol != protocol_handler->Protocol())
int32 index = 0;
PPPProtocol *protocol_handler = ProtocolFor(protocol, &index);
for(; protocol_handler; protocol_handler = ProtocolFor(protocol, &(++index))) {
if(!protocol_handler->IsEnabled()
|| !is_handler_allowed(*protocol_handler, State(), Phase()))
continue;
if(!protocol_handler->IsEnabled()) {
// disabled handlers should not be used
result = PPP_REJECTED;
continue;
}
// skip handler if disabled or not allowed
result = protocol_handler->Receive(packet, protocol);
if(result == PPP_UNHANDLED)
@ -899,7 +1117,7 @@ PPPInterface::Receive(struct mbuf *packet, uint16 protocol)
return result;
}
// maybe the parent interface can handle it
// maybe the parent interface can handle the packet
if(Parent())
return Parent()->Receive(packet, protocol);
@ -920,9 +1138,9 @@ PPPInterface::SendToDevice(struct mbuf *packet, uint16 protocol)
return B_ERROR;
// we must pass the basic tests like:
// do we have a device (as main interface)?
// do we have a device?
// did we load all modules?
if(InitCheck() != B_OK) {
if(InitCheck() != B_OK || !Device()) {
m_freem(packet);
return B_ERROR;
}
@ -934,21 +1152,23 @@ PPPInterface::SendToDevice(struct mbuf *packet, uint16 protocol)
}
// go up if DialOnDemand enabled and we are down
if(DoesDialOnDemand() && (Phase() == PPP_DOWN_PHASE
|| Phase() == PPP_ESTABLISHMENT_PHASE))
Up();
// Up() waits until it is done
if(DoesDialOnDemand()
&& (Phase() == PPP_DOWN_PHASE
|| Phase() == PPP_ESTABLISHMENT_PHASE)
&& !Up()) {
m_freem(packet);
return B_ERROR;
}
// check if protocol is allowed and everything is up
PPPProtocol *sending_protocol = ProtocolFor(protocol);
if(!fDevice->IsUp()
|| (!IsUp() && protocol != PPP_LCP_PROTOCOL
&& (!sending_protocol
|| sending_protocol->Flags() & PPP_ALWAYS_ALLOWED == 0
|| !sending_protocol->IsEnabled()
)
)
) {
// find the protocol handler for the current protocol number
int32 index = 0;
PPPProtocol *sending_protocol = ProtocolFor(protocol, &index);
while(sending_protocol && !sending_protocol->IsEnabled())
sending_protocol = ProtocolFor(protocol, &(++index));
// make sure that protocol is allowed to send and everything is up
if(!Device()->IsUp() || !sending_protocol || !sending_protocol->IsEnabled()
|| !is_handler_allowed(*sending_protocol, State(), Phase())){
m_freem(packet);
return B_ERROR;
}
@ -969,8 +1189,8 @@ PPPInterface::SendToDevice(struct mbuf *packet, uint16 protocol)
// pass to device/children
if(!IsMultilink() || Parent()) {
// check if packet is too big for device
if((packet->m_flags & M_PKTHDR && (uint32) packet->m_pkthdr.len > LinkMTU())
|| packet->m_len > LinkMTU()) {
if((packet->m_flags & M_PKTHDR && (uint32) packet->m_pkthdr.len > MRU())
|| packet->m_len > MRU()) {
m_freem(packet);
return B_ERROR;
}
@ -990,7 +1210,7 @@ PPPInterface::ReceiveFromDevice(struct mbuf *packet)
if(!packet)
return B_ERROR;
if(!InitCheck()) {
if(InitCheck() != B_OK) {
m_freem(packet);
return B_ERROR;
}
@ -999,14 +1219,7 @@ PPPInterface::ReceiveFromDevice(struct mbuf *packet)
uint16 *protocol = mtod(packet, uint16*);
*protocol = ntohs(*protocol);
m_adj(packet, sizeof(uint16));
// Set our interface as the receiver.
// This might be NULL, so protocols that belong to the network stack (IP, etc.)
// will probably be confused (as there is no interface from which the packet came).
// Protocols that live only in the PPP interface should have no problems with this.
if(packet->m_flags & M_PKTHDR)
packet->m_pkthdr.rcvif = Ifnet();
m_adj(packet, 2);
return Receive(packet, *protocol);
}
@ -1015,6 +1228,10 @@ PPPInterface::ReceiveFromDevice(struct mbuf *packet)
void
PPPInterface::Pulse()
{
if(fDeleteCounter > 0)
return;
// we have no pulse when we are dead ;)
// check our idle time and disconnect if needed
if(fDisconnectAfterIdleSince > 0 && fIdleSince != 0
&& fIdleSince - system_time() >= fDisconnectAfterIdleSince) {
@ -1041,7 +1258,7 @@ PPPInterface::RegisterInterface()
return true;
// we are already registered
if(!InitCheck())
if(InitCheck() != B_OK)
return false;
// we cannot register if something is wrong
@ -1085,9 +1302,9 @@ PPPInterface::UnregisterInterface()
void
PPPInterface::CalculateMRU()
PPPInterface::CalculateInterfaceMTU()
{
fMRU = fLinkMTU;
fInterfaceMTU = fMRU;
// sum all headers
fHeaderLength = sizeof(uint16);
@ -1096,15 +1313,15 @@ PPPInterface::CalculateMRU()
for(; encapsulator; encapsulator = encapsulator->Next())
fHeaderLength += encapsulator->Overhead();
fMRU -= fHeaderLength;
fInterfaceMTU -= fHeaderLength;
if(Ifnet()) {
Ifnet()->if_mtu = fMRU;
Ifnet()->if_mtu = fInterfaceMTU;
Ifnet()->if_hdrlen = fHeaderLength;
}
if(Parent())
Parent()->CalculateMRU();
Parent()->CalculateInterfaceMTU();
}
@ -1133,26 +1350,29 @@ PPPInterface::Redial()
return;
// start a new thread that calls our Up() method
redial_info *info = new redial_info;
info->interface = this;
info->thread = &fRedialThread;
redial_info info;
info.interface = this;
info.thread = &fRedialThread;
fRedialThread = spawn_thread(redial_func, "PPPInterface: redial_thread",
B_NORMAL_PRIORITY, info);
fRedialThread = spawn_thread(redial_thread, "PPPInterface: redial_thread",
B_NORMAL_PRIORITY, NULL);
resume_thread(fRedialThread);
send_data(fRedialThread, 0, &info, sizeof(redial_info));
}
status_t
redial_func(void *data)
redial_thread(void *data)
{
redial_info *info = (redial_info*) data;
redial_info info;
thread_id sender;
info->interface->Up();
*info->thread = -1;
receive_data(&sender, &info, sizeof(redial_info));
delete info;
info.interface->Up();
*info.thread = -1;
return B_OK;
}
@ -1182,3 +1402,12 @@ in_queue_thread(void *data)
return B_ERROR;
}
status_t
interface_deleter_thread(void *data)
{
delete (PPPInterface*) data;
return B_OK;
}

View File

@ -25,7 +25,7 @@
PPPLCP::PPPLCP(PPPInterface& interface)
: PPPProtocol("LCP", PPP_ESTABLISHMENT_PHASE, PPP_LCP_PROTOCOL,
AF_UNSPEC, &interface, NULL, PPP_ALWAYS_ALLOWED),
AF_UNSPEC, interface, NULL, PPP_ALWAYS_ALLOWED),
fStateMachine(interface.StateMachine()), fTarget(NULL)
{
SetUpRequested(false);
@ -87,8 +87,6 @@ PPPLCP::AdditionalOverhead() const
if(Target())
overhead += Target()->Overhead();
if(Interface()->Device())
overhead += Interface()->Device()->Overhead();
return overhead;
}
@ -113,10 +111,8 @@ PPPLCP::Send(struct mbuf *packet)
{
if(Target())
return Target()->Send(packet, PPP_LCP_PROTOCOL);
else if(Interface())
return Interface()->Send(packet, PPP_LCP_PROTOCOL);
else
return B_ERROR;
return Interface().Send(packet, PPP_LCP_PROTOCOL);
}
@ -171,7 +167,7 @@ PPPLCP::Receive(struct mbuf *packet, uint16 protocol)
break;
default:
return B_ERROR;
StateMachine().RUCEvent(packet, PPP_LCP_PROTOCOL, PPP_CODE_REJECT);
}
return B_OK;

View File

@ -7,8 +7,10 @@
#include <KPPPOptionHandler.h>
#include <PPPControl.h>
PPPOptionHandler::PPPOptionHandler(const char *name, PPPInterface *interface,
PPPOptionHandler::PPPOptionHandler(const char *name, PPPInterface& interface,
driver_parameter *settings)
: fInterface(interface), fSettings(settings)
{
@ -16,25 +18,53 @@ PPPOptionHandler::PPPOptionHandler(const char *name, PPPInterface *interface,
strncpy(fName, name, PPP_HANDLER_NAME_LENGTH_LIMIT);
fName[PPP_HANDLER_NAME_LENGTH_LIMIT] = 0;
} else
strcpy(fName, "");
strcpy(fName, "???");
if(interface)
interface->LCP().AddOptionHandler(this);
interface.LCP().AddOptionHandler(this);
}
PPPOptionHandler::~PPPOptionHandler()
{
if(Interface())
Interface()->LCP().RemoveOptionHandler(this);
Interface().LCP().RemoveOptionHandler(this);
}
status_t
PPPOptionHandler::InitCheck() const
{
if(!Interface() || !Settings())
if(!Settings())
return B_ERROR;
return B_OK;
}
status_t
PPPOptionHandler::Control(uint32 op, void *data, size_t length)
{
switch(op) {
case PPPC_GET_OPTION_HANDLER_INFO: {
if(length < sizeof(ppp_option_handler_info) || !data)
return B_ERROR;
ppp_option_handler_info *info = (ppp_option_handler_info*) data;
memset(info, 0, sizeof(ppp_option_handler_info));
strcpy(info->name, Name());
info->settings = Settings();
info->isEnabled = IsEnabled();
} break;
case PPPC_SET_ENABLED:
if(length < sizeof(uint32) || !data)
return B_ERROR;
SetEnabled(*((uint32*)data));
break;
default:
return PPP_UNHANDLED;
}
return B_OK;
}

View File

@ -7,11 +7,13 @@
#include <KPPPInterface.h>
#include <PPPControl.h>
#include <cstring>
PPPProtocol::PPPProtocol(const char *name, PPP_PHASE phase, uint16 protocol,
int32 addressFamily, PPPInterface *interface,
int32 addressFamily, PPPInterface& interface,
driver_parameter *settings, int32 flags = PPP_NO_FLAGS)
: fPhase(phase), fProtocol(protocol), fAddressFamily(addressFamily),
fInterface(interface), fSettings(settings), fFlags(flags),
@ -21,24 +23,22 @@ PPPProtocol::PPPProtocol(const char *name, PPP_PHASE phase, uint16 protocol,
strncpy(fName, name, PPP_HANDLER_NAME_LENGTH_LIMIT);
fName[PPP_HANDLER_NAME_LENGTH_LIMIT] = 0;
} else
strcpy(fName, "");
strcpy(fName, "???");
if(interface)
interface->AddProtocol(this);
interface.AddProtocol(this);
}
PPPProtocol::~PPPProtocol()
{
if(Interface())
Interface()->RemoveProtocol(this);
Interface().RemoveProtocol(this);
}
status_t
PPPProtocol::InitCheck() const
{
if(!Interface() || !Settings())
if(!Settings())
return B_ERROR;
return B_OK;
@ -50,13 +50,10 @@ PPPProtocol::SetEnabled(bool enabled = true)
{
fEnabled = enabled;
if(!Interface())
return;
if(!enabled) {
if(IsUp() || IsGoingUp())
Down();
} else if(!IsUp() && !IsGoingUp() && IsUpRequested() && Interface()->IsUp())
} else if(!IsUp() && !IsGoingUp() && IsUpRequested() && Interface().IsUp())
Up();
}
@ -65,16 +62,32 @@ status_t
PPPProtocol::Control(uint32 op, void *data, size_t length)
{
switch(op) {
// TODO:
// get:
// - name
// - protocol, address family
// - status (Is(Going)Up/Down/UpRequested/Enabled)
// set:
// - enabled
case PPPC_GET_HANDLER_INFO: {
if(length < sizeof(ppp_handler_info_t) || !data)
return B_ERROR;
ppp_handler_info *info = (ppp_handler_info*) data;
memset(info, 0, sizeof(ppp_handler_info_t));
strcpy(info->name, Name());
info->settings = Settings();
info->phase = Phase();
info->addressFamily = AddressFamily();
info->flags = Flags();
info->protocol = Protocol();
info->isEnabled = IsEnabled();
info->isUpRequested = IsUpRequested();
info->connectionStatus = fConnectionStatus;
} break;
case PPPC_SET_ENABLED:
if(length < sizeof(uint32) || !data)
return B_ERROR;
SetEnabled(*((uint32*)data));
break;
default:
return B_ERROR;
return PPP_UNHANDLED;
}
return B_OK;
@ -107,10 +120,7 @@ PPPProtocol::UpFailedEvent()
{
fConnectionStatus = PPP_DOWN_PHASE;
if(!Interface())
return;
Interface()->StateMachine().UpFailedEvent(this);
Interface().StateMachine().UpFailedEvent(this);
}
@ -119,10 +129,7 @@ PPPProtocol::UpEvent()
{
fConnectionStatus = PPP_ESTABLISHED_PHASE;
if(!Interface())
return;
Interface()->StateMachine().UpEvent(this);
Interface().StateMachine().UpEvent(this);
}
@ -131,8 +138,5 @@ PPPProtocol::DownEvent()
{
fConnectionStatus = PPP_DOWN_PHASE;
if(!Interface())
return;
Interface()->StateMachine().DownEvent(this);
Interface().StateMachine().DownEvent(this);
}

View File

@ -185,12 +185,12 @@ PPPStateMachine::UpEvent(PPPInterface *interface)
if(Phase() == PPP_ESTABLISHMENT_PHASE) {
// this is the first interface that went up
Interface()->SetLinkMTU(interface->LinkMTU());
Interface()->SetMRU(interface->MRU());
locker.UnlockNow();
ThisLayerUp();
} else if(Interface()->LinkMTU() > interface->LinkMTU())
Interface()->SetLinkMTU(interface->LinkMTU());
// linkMTU should always be the smallest value of all children
} else if(Interface()->MRU() > interface->MRU())
Interface()->SetMRU(interface->MRU());
// MRU should always be the smallest value of all children
NewState(PPP_OPENED_STATE);
}
@ -201,8 +201,8 @@ PPPStateMachine::DownEvent(PPPInterface *interface)
{
LockerHelper locker(fLock);
uint32 linkMTU = 0;
// the new linkMTU
uint32 MRU = 0;
// the new MRU
Interface()->CalculateBaudRate();
@ -214,17 +214,17 @@ PPPStateMachine::DownEvent(PPPInterface *interface)
child = Interface()->ChildAt(index);
if(child && child->IsUp()) {
// set linkMTU to the smallest value of all children
if(linkMTU == 0)
linkMTU = child->LinkMTU();
else if(linkMTU > child->LinkMTU())
linkMTU = child->LinkMTU();
// set MRU to the smallest value of all children
if(MRU == 0)
MRU = child->MRU();
else if(MRU > child->MRU())
MRU = child->MRU();
++count;
}
}
Interface()->SetLinkMTU(linkMTU);
Interface()->SetMRU(MRU);
if(count == 0) {
locker.UnlockNow();
@ -1463,10 +1463,10 @@ PPPStateMachine::SendCodeReject(struct mbuf *packet, uint16 protocol, uint8 type
int32 adjust = 0;
// adjust packet size by this value if packet is too big
if(packet->m_flags & M_PKTHDR) {
if((uint32) packet->m_pkthdr.len > Interface()->LinkMTU())
adjust = Interface()->LinkMTU() - packet->m_pkthdr.len;
} else if(packet->m_len > Interface()->LinkMTU())
adjust = Interface()->LinkMTU() - packet->m_len;
if((uint32) packet->m_pkthdr.len > Interface()->MRU())
adjust = Interface()->MRU() - packet->m_pkthdr.len;
} else if(packet->m_len > Interface()->MRU())
adjust = Interface()->MRU() - packet->m_len;
if(adjust != 0)
m_adj(packet, adjust);