Added MRU option handler.

Fixed wrong definition of MRU.
Added the StackControl() method to all handlers (expect PPPDevice) and changed how the netstack ioctls are passed to the handlers.
Added a template for iterating over indexed lists (needed methods: CountItems() and ItemAt()). This simplified StackControlEachHandler() a little bit.
Some minor changes.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4673 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Waldemar Kornewald
2003-09-14 13:24:24 +00:00
parent 7ff713dadd
commit c2a58f5169
20 changed files with 340 additions and 137 deletions
+4 -2
View File
@@ -33,10 +33,8 @@ class PPPDevice {
virtual status_t Control(uint32 op, void *data, size_t length);
virtual bool SetMTU(uint32 MTU);
uint32 MTU() const
{ return fMTU; }
virtual uint32 PreferredMTU() const = 0;
// these calls must not block
virtual void Up() = 0;
@@ -64,6 +62,9 @@ class PPPDevice {
virtual void Pulse();
protected:
void SetMTU(uint32 MTU)
{ fMTU = MTU; }
// Report that we are going up/down
// (from now on, the Up() process can be aborted).
// Abort if false is returned!
@@ -77,6 +78,7 @@ class PPPDevice {
protected:
uint32 fMTU;
// always hold this value up-to-date!
bool fIsUp;
status_t fInitStatus;
@@ -58,6 +58,8 @@ class PPPEncapsulator {
{ return fUpRequested; }
virtual status_t Control(uint32 op, void *data, size_t length);
virtual status_t StackControl(uint32 op, void *data);
// called by netstack (forwarded by PPPInterface)
void SetNext(PPPEncapsulator *next)
{ fNext = next; }
+12 -12
View File
@@ -36,17 +36,19 @@ struct ppp_module_info;
class PPPInterface {
friend class PPPStateMachine;
friend class PPPManager;
private:
// copies are not allowed!
PPPInterface(const PPPInterface& copy);
PPPInterface& operator= (const PPPInterface& copy);
public:
// only PPPManager may construct us!
PPPInterface(interface_id ID, driver_settings *settings,
PPPInterface *parent = NULL);
~PPPInterface();
public:
void Delete();
status_t InitCheck() const;
@@ -80,12 +82,12 @@ class PPPInterface {
uint32 DisconnectAfterIdleSince() const
{ return fDisconnectAfterIdleSince; }
void SetMRU(uint32 MRU);
bool SetMRU(uint32 MRU);
uint32 MRU() const
{ return fMRU; }
// this is the smallest MRU that we and the peer have
void SetInterfaceMTU(uint32 interfaceMTU)
{ SetMRU(interfaceMTU - fHeaderLength); }
bool SetInterfaceMTU(uint32 interfaceMTU)
{ return SetMRU(interfaceMTU - fHeaderLength); }
uint32 InterfaceMTU() const
{ return fInterfaceMTU; }
// this is the MRU including encapsulator overhead
@@ -125,11 +127,11 @@ class PPPInterface {
bool IsMultilink() const
{ return fIsMultilink; }
void SetAutoRedial(bool autoredial = true);
void SetAutoRedial(bool autoRedial = true);
bool DoesAutoRedial() const
{ return fAutoRedial; }
void SetDialOnDemand(bool dialondemand = true);
void SetDialOnDemand(bool dialOnDemand = true);
bool DoesDialOnDemand() const
{ return fDialOnDemand; }
@@ -192,14 +194,12 @@ class PPPInterface {
status_t StackControl(uint32 op, void *data);
// stack routes ioctls to interface
status_t ControlEachHandler(uint32 op, void *data, size_t length);
// this calls Control() with the given parameters for each handler
status_t StackControlEachHandler(uint32 op, void *data);
// this calls StackControl() with the given parameters for each handler
void CalculateInterfaceMTU();
void CalculateBaudRate();
bool SetupDialOnDemand();
void Redial(uint32 delay);
// multilink methods
@@ -40,6 +40,8 @@ class PPPLCPExtension {
{ return fCode; }
virtual status_t Control(uint32 op, void *data, size_t length);
virtual status_t StackControl(uint32 op, void *data);
// called by netstack (forwarded by PPPInterface)
virtual status_t Receive(struct mbuf *packet, uint8 code) = 0;
@@ -42,6 +42,8 @@ class PPPOptionHandler {
{ return fEnabled; }
virtual status_t Control(uint32 op, void *data, size_t length);
virtual status_t StackControl(uint32 op, void *data);
// called by netstack (forwarded by PPPInterface)
// we want to send a configure request or we received a reply
virtual status_t AddToRequest(PPPConfigurePacket& request) = 0;
@@ -55,15 +55,12 @@ class PPPProtocol {
{ return fUpRequested; }
virtual status_t Control(uint32 op, void *data, size_t length);
virtual status_t SetupDialOnDemand();
// This is not called when the protocol is added to the interface,
// but only when someone enables DialOnDemand and interface is down.
// Of course, your constructor may/should use this method (if needed).
virtual status_t StackControl(uint32 op, void *data);
// called by netstack (forwarded by PPPInterface)
virtual bool Up() = 0;
virtual bool Down() = 0;
// if DialOnDemand is implemented check for DialOnDemand settings change
// if DialOnDemand is supported check for DialOnDemand settings change
bool IsUp() const
{ return fConnectionStatus == PPP_ESTABLISHED_PHASE; }
bool IsDown() const
@@ -31,6 +31,16 @@ is_handler_allowed(T& handler, ppp_state state, ppp_phase phase)
return false;
}
// the list template does not support iterating over each item :(
// this template iterates over each item in an indexed list
template<class _LIST, class _FUNCTION>
inline
void
ForEachItem(_LIST& list, _FUNCTION function)
{
for(int index = 0; index < list.CountItems(); index++)
function(list.ItemAt(index));
}
// These are very simple send/receive_data functions with a timeout
// and there is a race condition beween has_data() and send/receive_data().
+1 -5
View File
@@ -59,10 +59,6 @@ enum ppp_control_ops {
PPPC_SET_ENABLED,
PPPC_GET_SIMPLE_HANDLER_INFO,
// PPPOptionHandler and PPPLCPExtension
PPPC_STACK_IOCTL,
// Ioctls from the stack are passed to all handlers and the interface
// using a ppp_control_info (only op and data are defined!).
// You should return B_BAD_VALUE if you did not handle this ioctl.
// -----------------------------------------------------
PPP_CONTROL_OPS_END = B_DEVICE_OP_CODES_END + 0xFFFF
@@ -119,7 +115,7 @@ typedef struct ppp_device_info {
const driver_parameter *settings;
uint32 MTU, preferredMTU;
uint32 MTU;
uint32 inputTransferRate, outputTransferRate, outputBytesCount;
} ppp_device_info;
typedef struct ppp_device_info_t {
-1
View File
@@ -50,7 +50,6 @@ enum {
PPP_UNHANDLED = PPP_ERROR_BASE,
// The packet does not belong to this handler.
// Do not delete the packet when you return this!
// For PPPOptionHandler: the item is unrecognized
// return values of PPPInterface::Receive()
PPP_DISCARDED,
+1 -1
View File
@@ -25,6 +25,6 @@ R5KernelStaticLibrary kernelppp :
cpp.cpp
# integrated modules
_KPPPMRUHandler.cpp
_KPPPPFCHandler.cpp
;
@@ -56,7 +56,6 @@ PPPDevice::Control(uint32 op, void *data, size_t length)
strcpy(info->name, Name());
info->settings = Settings();
info->MTU = MTU();
info->preferredMTU = PreferredMTU();
info->inputTransferRate = InputTransferRate();
info->outputTransferRate = OutputTransferRate();
info->outputBytesCount = CountOutputBytes();
@@ -102,6 +102,18 @@ PPPEncapsulator::Control(uint32 op, void *data, size_t length)
}
status_t
PPPEncapsulator::StackControl(uint32 op, void *data)
{
switch(op) {
default:
return B_BAD_VALUE;
}
return B_OK;
}
status_t
PPPEncapsulator::SendToNext(struct mbuf *packet, uint16 protocol) const
{
+80 -101
View File
@@ -32,6 +32,7 @@
#include "settings_tools.h"
// internal modules
#include "_KPPPMRUHandler.h"
#include "_KPPPPFCHandler.h"
@@ -68,7 +69,7 @@ PPPInterface::PPPInterface(uint32 ID, driver_settings *settings,
fDialRetriesLimit(0),
fIdleSince(0),
fMRU(1500),
fInterfaceMTU(1498),
fInterfaceMTU(1500),
fHeaderLength(2),
fAutoRedial(false),
fDialOnDemand(false),
@@ -81,6 +82,12 @@ PPPInterface::PPPInterface(uint32 ID, driver_settings *settings,
fDeleteCounter(0)
{
// add internal modules
// MRU
_PPPMRUHandler *mruHandler =
new _PPPMRUHandler(*this);
if(mruHandler->InitCheck() != B_OK)
delete mruHandler;
// PFC
_PPPPFCHandler *pfcHandler =
new _PPPPFCHandler(fLocalPFCState, fPeerPFCState, *this);
if(pfcHandler->InitCheck() != B_OK)
@@ -255,14 +262,19 @@ PPPInterface::InitCheck() const
}
void
bool
PPPInterface::SetMRU(uint32 MRU)
{
if(MRU > Device()->MTU() - 2)
return false;
LockerHelper locker(fLock);
fMRU = MRU;
CalculateInterfaceMTU();
return true;
}
@@ -420,17 +432,6 @@ PPPInterface::Control(uint32 op, void *data, size_t length)
return child->Control(control->op, control->data, control->length);
} break;
case PPPC_STACK_IOCTL: {
if(length < sizeof(ppp_control_info) || !data)
return B_ERROR;
ppp_control_info *control = (ppp_control_info*) data;
if(StackControl(control->op, control->data) == B_BAD_VALUE)
return ControlEachHandler(op, data, length);
return B_OK;
} break;
default:
return B_BAD_VALUE;
}
@@ -460,7 +461,7 @@ PPPInterface::SetDevice(PPPDevice *device)
fDevice = device;
fMRU = fDevice->MTU();
fMRU = fDevice->MTU() - 2;
CalculateInterfaceMTU();
CalculateBaudRate();
@@ -727,47 +728,54 @@ PPPInterface::ChildAt(int32 index) const
void
PPPInterface::SetAutoRedial(bool autoredial = true)
PPPInterface::SetAutoRedial(bool autoRedial = true)
{
if(Mode() == PPP_CLIENT_MODE)
return;
LockerHelper locker(fLock);
fAutoRedial = autoredial;
fAutoRedial = autoRedial;
}
void
PPPInterface::SetDialOnDemand(bool dialondemand = true)
PPPInterface::SetDialOnDemand(bool dialOnDemand = true)
{
// All protocols must check if DialOnDemand was enabled/disabled after this
// interface went down. This is the only situation where a change is relevant.
// only clients support DialOnDemand
if(Mode() != PPP_CLIENT_MODE)
// Only clients support DialOnDemand. Maybe no change needed.
if(Mode() != PPP_CLIENT_MODE || DoesDialOnDemand() == dialOnDemand)
return;
LockerHelper locker(fLock);
if(DoesDialOnDemand() && !dialondemand && State() != PPP_OPENED_STATE) {
// as long as the protocols were not configured we can just delete us
Delete();
fDialOnDemand = dialOnDemand;
// Do not allow changes when we are disconnected (only main interfaces).
// This would make no sense because
// - enabling: this cannot happen because hidden interfaces are deleted if they
// could not establish a connection (the user cannot access hidden interfaces)
// - disabling: the interface disappears as seen from the user, so we delete it
if(!Parent() && State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE) {
if(!dialOnDemand)
Delete();
// as long as the protocols were not configured we can just delete us
return;
}
fDialOnDemand = dialondemand;
// check if we need to register/unregister
if(fDialOnDemand) {
if(dialOnDemand) {
RegisterInterface();
if(Ifnet())
Ifnet()->if_flags |= IFF_RUNNING;
} else if(!fDialOnDemand && Phase() < PPP_ESTABLISHED_PHASE) {
} else if(!dialOnDemand && Phase() < PPP_ESTABLISHED_PHASE) {
UnregisterInterface();
// if we are already down we must delete us
if(Phase() == PPP_DOWN_PHASE)
if(State() == PPP_INITIAL_STATE && Phase() == PPP_DOWN_PHASE)
Delete();
}
}
@@ -1414,7 +1422,6 @@ PPPInterface::RegisterInterface()
return false;
CalculateBaudRate();
SetupDialOnDemand();
return true;
}
@@ -1443,7 +1450,7 @@ PPPInterface::UnregisterInterface()
}
// stack routes ioctls to interface
// called by PPPManager: manager routes stack ioctls to interface
status_t
PPPInterface::StackControl(uint32 op, void *data)
{
@@ -1452,75 +1459,59 @@ PPPInterface::StackControl(uint32 op, void *data)
switch(op) {
default:
return B_BAD_VALUE;
return StackControlEachHandler(op, data);
}
return B_OK;
}
// used by ControlEachHandler()
template<class T>
class CallStackControl {
public:
inline CallStackControl(uint32 op, void *data, status_t& result)
: fOp(op), fData(data), fResult(result) {}
inline void operator() (T *item)
{
if(!item || !item->IsEnabled())
return;
status_t tmp = item->StackControl(fOp, fData);
if(tmp == B_OK && fResult == B_BAD_VALUE)
fResult = B_OK;
else if(tmp != B_BAD_VALUE)
fResult = tmp;
}
private:
uint32 fOp;
void *fData;
status_t& fResult;
};
// This calls Control() with the given parameters for each handler.
// Return values:
// B_OK: all handlers returned B_OK
// B_BAD_VALUE: no handler was found
// any other value: the error value that was returned by the last handler that failed
status_t
PPPInterface::ControlEachHandler(uint32 op, void *data, size_t length)
PPPInterface::StackControlEachHandler(uint32 op, void *data)
{
int32 index;
status_t result = B_BAD_VALUE, tmp;
// protocols
PPPProtocol *protocol;
for(index = 0; index < CountProtocols(); index++) {
protocol = ProtocolAt(index);
if(!protocol)
break;
tmp = protocol->Control(op, data, length);
if(tmp == B_OK && result == B_BAD_VALUE)
result = B_OK;
else if(tmp != B_BAD_VALUE)
result = tmp;
}
// encapsulators
PPPEncapsulator *encapsulator = FirstEncapsulator();
for(; encapsulator; encapsulator = encapsulator->Next()) {
tmp = encapsulator->Control(op, data, length);
tmp = encapsulator->StackControl(op, data);
if(tmp == B_OK && result == B_BAD_VALUE)
result = B_OK;
else if(tmp != B_BAD_VALUE)
result = tmp;
}
// option handlers
PPPOptionHandler *optionHandler;
for(index = 0; index < LCP().CountOptionHandlers(); index++) {
optionHandler = LCP().OptionHandlerAt(index);
if(!optionHandler)
break;
tmp = optionHandler->Control(op, data, length);
if(tmp == B_OK && result == B_BAD_VALUE)
result = B_OK;
else if(tmp != B_BAD_VALUE)
result = tmp;
}
// LCP extensions
PPPLCPExtension *lcpExtension;
for(index = 0; index < LCP().CountLCPExtensions(); index++) {
lcpExtension = LCP().LCPExtensionAt(index);
if(!lcpExtension)
break;
tmp = lcpExtension->Control(op, data, length);
if(tmp == B_OK && result == B_BAD_VALUE)
result = B_OK;
else if(tmp != B_BAD_VALUE)
result = tmp;
}
ForEachItem(fProtocols, CallStackControl<PPPProtocol>(op, data, result));
ForEachItem(LCP().fLCPExtensions,
CallStackControl<PPPLCPExtension>(op, data, result));
ForEachItem(LCP().fOptionHandlers,
CallStackControl<PPPOptionHandler>(op, data, result));
return result;
}
@@ -1531,9 +1522,7 @@ PPPInterface::CalculateInterfaceMTU()
{
fInterfaceMTU = fMRU;
// sum all headers
fHeaderLength = sizeof(uint16);
// sum all headers (the protocol field is not counted)
PPPEncapsulator *encapsulator = fFirstEncapsulator;
for(; encapsulator; encapsulator = encapsulator->Next())
fHeaderLength += encapsulator->Overhead();
@@ -1568,28 +1557,6 @@ PPPInterface::CalculateBaudRate()
}
bool
PPPInterface::SetupDialOnDemand()
{
LockerHelper locker(fLock);
if(State() == PPP_OPENED_STATE)
return true;
bool result = true;
PPPProtocol *protocol;
for(int32 index = 0; index < CountProtocols(); index++) {
protocol = ProtocolAt(index);
if(protocol && protocol->IsEnabled())
if(protocol->SetupDialOnDemand() != B_OK)
result = false;
}
return result;
}
void
PPPInterface::Redial(uint32 delay)
{
@@ -1660,10 +1627,22 @@ in_queue_thread(void *data)
}
// ----------------------------------
// Function: interface_deleter_thread
// ----------------------------------
// The destructor is private, so this thread function cannot delete our interface.
// To solve this problem we create a 'fake' class PPPManager (friend of PPPInterface)
// which is only defined here (the real class is defined in the ppp_manager module).
class PPPManager {
public:
PPPManager(PPPInterface *interface)
{ if(interface) delete interface; }
};
status_t
interface_deleter_thread(void *data)
{
delete (PPPInterface*) data;
PPPManager((PPPInterface*) data);
return B_OK;
}
+1 -4
View File
@@ -18,9 +18,6 @@
#include <sys/socket.h>
#define PPP_PROTOCOL_OVERHEAD 2
PPPLCP::PPPLCP(PPPInterface& interface)
: PPPProtocol("LCP", PPP_ESTABLISHMENT_PHASE, PPP_LCP_PROTOCOL,
AF_UNSPEC, interface, NULL, PPP_ALWAYS_ALLOWED),
@@ -177,7 +174,7 @@ PPPLCP::LCPExtensionFor(uint8 code, int32 *start = NULL) const
uint32
PPPLCP::AdditionalOverhead() const
{
uint32 overhead = PPP_PROTOCOL_OVERHEAD;
uint32 overhead = 0;
if(Target())
overhead += Target()->Overhead();
@@ -70,6 +70,18 @@ PPPLCPExtension::Control(uint32 op, void *data, size_t length)
}
status_t
PPPLCPExtension::StackControl(uint32 op, void *data)
{
switch(op) {
default:
return B_BAD_VALUE;
}
return B_OK;
}
void
PPPLCPExtension::Reset()
{
@@ -68,3 +68,15 @@ PPPOptionHandler::Control(uint32 op, void *data, size_t length)
return B_OK;
}
status_t
PPPOptionHandler::StackControl(uint32 op, void *data)
{
switch(op) {
default:
return B_BAD_VALUE;
}
return B_OK;
}
+6 -1
View File
@@ -105,8 +105,13 @@ PPPProtocol::Control(uint32 op, void *data, size_t length)
status_t
PPPProtocol::SetupDialOnDemand()
PPPProtocol::StackControl(uint32 op, void *data)
{
switch(op) {
default:
return B_BAD_VALUE;
}
return B_OK;
}
@@ -313,7 +313,10 @@ PPPStateMachine::DownEvent(PPPInterface& interface)
}
}
Interface().SetMRU(MRU);
if(MRU == 0)
Interface().SetMRU(1500);
else
Interface().SetMRU(MRU);
if(count == 0) {
locker.UnlockNow();
@@ -1341,7 +1344,7 @@ PPPStateMachine::RCREvent(struct mbuf *packet)
result = handler->ParseRequest(request, index, nak, reject);
if(result != B_OK && result != PPP_UNHANDLED) {
if(result != B_OK) {
// the request contains a value that has been sent more than
// once or the value is corrupted
m_freem(packet);
@@ -1359,7 +1362,7 @@ PPPStateMachine::RCREvent(struct mbuf *packet)
result = handler->ParseRequest(request, request.CountItems(),
nak, reject);
if(result != B_OK && result != PPP_UNHANDLED) {
if(result != B_OK) {
// the request contains a value that has been sent more than
// once or the value is corrupted
m_freem(packet);
@@ -0,0 +1,140 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//
// Copyright (c) 2003 Waldemar Kornewald, [email protected]
//---------------------------------------------------------------------
#include "_KPPPMRUHandler.h"
#include <KPPPConfigurePacket.h>
#include <KPPPDevice.h>
#include <netinet/in.h>
#define MRU_TYPE 0x1
typedef struct mru_item {
uint8 type;
uint8 length;
uint16 MRU;
};
status_t ParseRequestedItem(mru_item *item, PPPInterface& interface);
_PPPMRUHandler::_PPPMRUHandler(PPPInterface& interface)
: PPPOptionHandler("MRU Handler", MRU_TYPE, interface, NULL)
{
Reset();
}
status_t
_PPPMRUHandler::AddToRequest(PPPConfigurePacket& request)
{
if(!Interface().Device() || Interface().MRU() == 1500)
return B_OK;
// add MRU request
mru_item item;
item.type = MRU_TYPE;
item.length = 4;
item.MRU = htons(fLocalMRU);
return request.AddItem((ppp_configure_item*) &item) ? B_OK : B_ERROR;
}
status_t
_PPPMRUHandler::ParseNak(const PPPConfigurePacket& nak)
{
mru_item *item = (mru_item*) nak.ItemWithType(MRU_TYPE);
if(!item || item->length != 4)
return B_OK;
uint16 MRU = ntohs(item->MRU);
if(MRU < fLocalMRU)
fLocalMRU = MRU;
return B_OK;
}
status_t
_PPPMRUHandler::ParseReject(const PPPConfigurePacket& reject)
{
if(reject.ItemWithType(MRU_TYPE))
return B_ERROR;
return B_OK;
}
status_t
_PPPMRUHandler::ParseAck(const PPPConfigurePacket& ack)
{
uint16 MRU = 1500;
mru_item *item = (mru_item*) ack.ItemWithType(MRU_TYPE);
if(item)
MRU = ntohs(item->MRU);
if(MRU < Interface().MRU())
fLocalMRU = MRU;
return B_OK;
}
status_t
_PPPMRUHandler::ParseRequest(const PPPConfigurePacket& request,
int32 index, PPPConfigurePacket& nak, PPPConfigurePacket& reject)
{
if(index == reject.CountItems())
return B_OK;
return ParseRequestedItem((mru_item*) request.ItemAt(index), Interface());
return B_OK;
}
status_t
_PPPMRUHandler::SendingAck(const PPPConfigurePacket& ack)
{
return ParseRequestedItem((mru_item*) ack.ItemWithType(MRU_TYPE), Interface());
}
// this function contains code shared by ParseRequest and SendingAck
status_t
ParseRequestedItem(mru_item *item, PPPInterface& interface)
{
uint16 MRU = 1500;
if(item) {
if(item->length != 4)
return B_ERROR;
// the request had a corrupted item
MRU = ntohs(item->MRU);
}
if(MRU < interface.MRU())
interface.SetMRU(MRU);
return B_OK;
}
void
_PPPMRUHandler::Reset()
{
if(Interface().Device()) {
fLocalMRU = Interface().Device()->MTU() - 2;
Interface().SetMRU(fLocalMRU);
} else {
Interface().SetMRU(1500);
fLocalMRU = 1500;
}
}
@@ -0,0 +1,34 @@
//----------------------------------------------------------------------
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//
// Copyright (c) 2003 Waldemar Kornewald, [email protected]
//---------------------------------------------------------------------
#ifndef __K_PPP_MRU_HANDLER__H
#define __K_PPP_MRU_HANDLER__H
#include <KPPPOptionHandler.h>
class _PPPMRUHandler : public PPPOptionHandler {
public:
_PPPMRUHandler(PPPInterface& interface);
virtual status_t AddToRequest(PPPConfigurePacket& request);
virtual status_t ParseNak(const PPPConfigurePacket& nak);
virtual status_t ParseReject(const PPPConfigurePacket& reject);
virtual status_t ParseAck(const PPPConfigurePacket& ack);
virtual status_t ParseRequest(const PPPConfigurePacket& request,
int32 index, PPPConfigurePacket& nak, PPPConfigurePacket& reject);
virtual status_t SendingAck(const PPPConfigurePacket& ack);
virtual void Reset();
private:
uint16 fLocalMRU;
};
#endif