PPPReportManager had some old port code.

Added checking for sender to report system.
Worked on StateMachine and added cases where the interface should be deleted.
Added some flags (report and protocol) and report codes.
Started implementing Up().
Some minor changes (comments, multilink).


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4108 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Waldemar Kornewald 2003-07-27 11:54:35 +00:00
parent ebf34d2339
commit 4d1fb4b669
8 changed files with 163 additions and 42 deletions

View File

@ -65,10 +65,12 @@ enum {
PPP_NO_FLAGS = 0x00, PPP_NO_FLAGS = 0x00,
PPP_ALWAYS_ALLOWED = 0x01, PPP_ALWAYS_ALLOWED = 0x01,
// protocol may send/receive in PPP_ESTABLISHMENT_PHASE // protocol may send/receive in PPP_ESTABLISHMENT_PHASE
PPP_NEEDS_DOWN = 0x02 PPP_NEEDS_DOWN = 0x02,
// protocol needs a Down() in addition to a Reset() to // protocol needs a Down() in addition to a Reset() to
// terminate the connection properly (losing the connection // terminate the connection properly (losing the connection
// still results in a Reset() only) // still results in a Reset() only)
PPP_NOT_IMPORTANT = 0x03
// if this protocol fails to go up we do not disconnect
}; };
// phase when the protocol is brought up // phase when the protocol is brought up

View File

@ -29,6 +29,7 @@ class PPPDevice {
{ return fMTU; } { return fMTU; }
virtual uint32 PreferredMTU() const = 0; virtual uint32 PreferredMTU() const = 0;
// these calls must not block
virtual void Up() = 0; virtual void Up() = 0;
virtual void Down() = 0; virtual void Down() = 0;
virtual void Listen() = 0; virtual void Listen() = 0;

View File

@ -19,6 +19,8 @@ class PPPOptionHandler;
class PPPInterface { class PPPInterface {
friend class PPPStateMachine;
private: private:
// copies are not allowed! // copies are not allowed!
PPPInterface(const PPPInterface& copy); PPPInterface(const PPPInterface& copy);
@ -136,6 +138,7 @@ class PPPInterface {
PPPLCP fLCP; PPPLCP fLCP;
PPPReportManager fReportManager; PPPReportManager fReportManager;
ifnet *fIfnet; ifnet *fIfnet;
thread_id fUpThread;
ppp_manager_info *fManager; ppp_manager_info *fManager;

View File

@ -11,7 +11,8 @@
enum PPP_REPORT_FLAGS { enum PPP_REPORT_FLAGS {
PPP_NO_REPORT_FLAGS = 0, PPP_NO_REPORT_FLAGS = 0,
PPP_WAIT_FOR_REPLY = 0x1, PPP_WAIT_FOR_REPLY = 0x1,
PPP_REMOVE_AFTER_REPORT = 0x2 PPP_REMOVE_AFTER_REPORT = 0x2,
PPP_NO_REPLY_TIMEOUT = 0x4
}; };
// report types // report types
@ -23,6 +24,7 @@ enum PPP_REPORT_TYPE {
// report codes (type-specific) // report codes (type-specific)
enum PPP_CONNECTION_REPORT_CODES { enum PPP_CONNECTION_REPORT_CODES {
PPP_GOING_UP = 0,
PPP_UP_SUCCESSFUL = 1, PPP_UP_SUCCESSFUL = 1,
PPP_DOWN_SUCCESSFUL = 2, PPP_DOWN_SUCCESSFUL = 2,
PPP_UP_ABORTED = 3, PPP_UP_ABORTED = 3,

View File

@ -7,6 +7,8 @@
#include "LockerHelper.h" #include "LockerHelper.h"
#define PPP_REPLY(sender, value) send_data_with_timeout((sender), (value), NULL, 0, B_REPORT_TIMEOUT)
class PPPReportManager { class PPPReportManager {
public: public:
PPPReportManager(BLocker& lock); PPPReportManager(BLocker& lock);

View File

@ -26,7 +26,7 @@
PPPInterface::PPPInterface(driver_settings *settings, PPPInterface *parent = NULL) PPPInterface::PPPInterface(driver_settings *settings, PPPInterface *parent = NULL)
: fSettings(dup_driver_settings(settings)), : fSettings(dup_driver_settings(settings)),
fStateMachine(*this), fLCP(*this), fReportManager(StateMachine().Locker()), fStateMachine(*this), fLCP(*this), fReportManager(StateMachine().Locker()),
fIfnet(NULL), fLinkMTU(1500), fAccessing(0), fChildrenCount(0), fIfnet(NULL), fUpThread(-1), fLinkMTU(1500), fAccessing(0), fChildrenCount(0),
fDevice(NULL), fFirstEncapsulator(NULL), fLock(StateMachine().Locker()) fDevice(NULL), fFirstEncapsulator(NULL), fLock(StateMachine().Locker())
{ {
if(get_module(PPP_MANAGER_MODULE_NAME, (module_info**) &fManager) != B_OK) if(get_module(PPP_MANAGER_MODULE_NAME, (module_info**) &fManager) != B_OK)
@ -344,6 +344,9 @@ PPPInterface::EncapsulatorFor(uint16 protocol,
bool bool
PPPInterface::AddChild(PPPInterface *child) PPPInterface::AddChild(PPPInterface *child)
{ {
if(!child || child->Mode() != Mode())
return false;
LockerHelper locker(fLock); LockerHelper locker(fLock);
if(fChildren.HasItem(child) || !fChildren.AddItem(child)) if(fChildren.HasItem(child) || !fChildren.AddItem(child))
@ -402,28 +405,88 @@ PPPInterface::SetDialOnDemand(bool dialondemand = true)
// check if we need to register/unregister // check if we need to register/unregister
if(!Ifnet() && fDialOnDemand) if(!Ifnet() && fDialOnDemand)
RegisterInterface(); RegisterInterface();
else if(Ifnet() && !fDialOnDemand && Phase() == PPP_DOWN_PHASE) else if(Ifnet() && !fDialOnDemand && Phase() == PPP_DOWN_PHASE) {
UnregisterInterface(); UnregisterInterface();
Delete();
}
} }
bool bool
PPPInterface::Up() PPPInterface::Up()
{ {
// ToDo: if(!InitCheck() || Phase() == PPP_TERMINATION_PHASE)
// instead of waiting for state change we should wait until
// all retries are done
if(!InitCheck() || Phase() != PPP_DOWN_PHASE)
return false; return false;
if(IsUp()) if(IsUp())
return true; return true;
// TODO: ppp_report_packet report;
// Add one-time connection report request and wait thread_id me = find_thread(NULL), sender;
// for results. If we lost the connection we should
// consider redialing. // one thread has to do the real task while all other threads are observers
fLock.Lock();
if(fUpThread == -1)
fUpThread = me;
fReportManager.EnableReports(PPP_CONNECTION_REPORT, me, PPP_WAIT_FOR_REPLY);
fLock.Unlock();
if(me != fUpThread) {
// I am an observer
while(true) {
if(IsUp()) {
fReportManager.DisableReports(PPP_CONNECTION_REPORT, me);
return true;
}
if(receive_data(&sender, &report, sizeof(report)) != PPP_REPORT_CODE) {
fReportManager.DisableReports(PPP_CONNECTION_REPORT, me);
return true;
}
if(IsUp()) {
PPP_REPLY(sender, B_OK);
fReportManager.DisableReports(PPP_CONNECTION_REPORT, me);
return true;
}
if(report.type != PPP_CONNECTION_REPORT) {
PPP_REPLY(sender, B_OK);
fReportManager.DisableReports(PPP_CONNECTION_REPORT, me);
}
if(report.code == PPP_GOING_UP) {
PPP_REPLY(sender, B_OK);
continue;
} else if(report.code == PPP_UP_SUCCESSFUL) {
PPP_REPLY(sender, B_OK);
fReportManager.DisableReports(PPP_CONNECTION_REPORT, me);
return true;
} else if(report.code == PPP_DOWN_SUCCESSFUL
|| report.code == PPP_UP_ABORTED) {
PPP_REPLY(sender, B_OK);
fReportManager.DisableReports(PPP_CONNECTION_REPORT, me);
return false;
} else if(report.code == PPP_UP_FAILED) {
// TODO:
// if maximum number of retries is reached we return false
// otherwise we wait for the next dial-attempt
} else if(report.code == PPP_AUTHENTICATION_FAILED) {
PPP_REPLY(sender, B_OK);
fReportManager.DisableReports(PPP_CONNECTION_REPORT, me);
return false;
} else if(report.code == PPP_CONNECTION_LOST) {
// TODO:
// if autoredial is enabled wait for redial attemts (just continue)
}
}
} else {
// I am the thread for the real task
while(true) {
}
}
return false; return false;
} }

View File

@ -82,7 +82,7 @@ PPPReportManager::Report(PPP_REPORT_TYPE type, int32 code, void *data, int32 len
for(int32 index = 0; index < fReportRequests.CountItems(); index++) { for(int32 index = 0; index < fReportRequests.CountItems(); index++) {
ppp_report_request& request = fReportRequests.ItemAt(index); ppp_report_request& request = fReportRequests.ItemAt(index);
result = send_data_with_timeout(request.port, PPP_REPORT_CODE, &report, result = send_data_with_timeout(request.thread, PPP_REPORT_CODE, &report,
sizeof(report), PPP_REPORT_TIMEOUT); sizeof(report), PPP_REPORT_TIMEOUT);
if(result == B_BAD_THREAD_ID || result == B_NO_MEMORY) { if(result == B_BAD_THREAD_ID || result == B_NO_MEMORY) {
@ -91,10 +91,21 @@ PPPReportManager::Report(PPP_REPORT_TYPE type, int32 code, void *data, int32 len
continue; continue;
} else if(result == B_OK) { } else if(result == B_OK) {
if(request.flags & PPP_WAIT_FOR_REPLY) { if(request.flags & PPP_WAIT_FOR_REPLY) {
result = receive_data_with_timeout(fPort, &code, NULL, 0, if(request.flags & PPP_NO_REPLY_TIMEOUT) {
PPP_REPORT_TIMEOUT); sender = -1;
while(sender != request.thread)
code = receive_data(&sender, NULL, 0);
result = B_OK;
} else {
sender = -1;
result = B_OK;
while(sender != request.thread && result == B_OK)
result = receive_data_with_timeout(&sender, &code, NULL, 0,
PPP_REPORT_TIMEOUT);
}
if(result == B_OK && code != B_OK) if(result == B_OK && code != B_OK)
successful = false; acceptable = false;
} }
} }

View File

@ -2,7 +2,11 @@
// TODO: // TODO:
// do not forget to reset authentication status when needed // do not forget to reset authentication status when:
// - connection is lost
// - reconfiguring?
// - terminating
// - ...
PPPStateMachine::PPPStateMachine(PPPInterface& interface) PPPStateMachine::PPPStateMachine(PPPInterface& interface)
: fInterface(&interface), fPhase(PPP_DOWN_PHASE), : fInterface(&interface), fPhase(PPP_DOWN_PHASE),
@ -49,8 +53,16 @@ PPPStateMachine::NewPhase(PPP_PHASE next)
{ {
// Report a down event to parent if we are not usable anymore. // Report a down event to parent if we are not usable anymore.
// The report threads get their notification later. // The report threads get their notification later.
if(Phase() == PPP_ESTABLISHED_PHASE && Interface()->Parent()) if(Phase() == PPP_ESTABLISHED_PHASE && next != Phase()) {
Interface()->Parent()->StateMachine().DownEvent(Interface()); if(Interface()->Ifnet())
Interface()->Ifnet()->if_flags &= ~IFF_RUNNING;
if(!Interface()->DoesDialOnDemand())
Interface()->UnregisterInterface();
if(Interface()->Parent())
Interface()->Parent()->StateMachine().DownEvent(Interface());
}
// there is nothing after established phase and nothing before down phase // there is nothing after established phase and nothing before down phase
if(next > PPP_ESTABLISHED_PHASE) if(next > PPP_ESTABLISHED_PHASE)
@ -161,13 +173,14 @@ PPPStateMachine::UpEvent(PPPInterface *interface)
LockerHelper locker(fLock); LockerHelper locker(fLock);
if(Phase() <= PPP_TERMINATION_PHASE || State() != PPP_STARTING_STATE) { if(Phase() <= PPP_TERMINATION_PHASE || State() != PPP_STARTING_STATE) {
interface->Down(); interface->StateMachine().CloseEvent();
return; return;
} }
NewState(PPP_OPENED_STATE); NewState(PPP_OPENED_STATE);
if(Phase() == PPP_ESTABLISHMENT_PHASE) { if(Phase() == PPP_ESTABLISHMENT_PHASE) {
NewPhase(PPP_AUTHENTICATION_PHASE); NewPhase(PPP_AUTHENTICATION_PHASE);
locker.UnlockNow();
ThisLayerUp(); ThisLayerUp();
} }
} }
@ -189,8 +202,10 @@ PPPStateMachine::DownEvent(PPPInterface *interface)
++count; ++count;
} }
if(count == 0 && Interface()->Ifnet()) if(count == 0) {
Interface()->Ifnet()->if_flags &= ~IFF_RUNNING; locker.UnlockNow();
DownEvent();
}
} }
} }
@ -198,8 +213,8 @@ PPPStateMachine::DownEvent(PPPInterface *interface)
void void
PPPStateMachine::UpFailedEvent(PPPProtocol *protocol) PPPStateMachine::UpFailedEvent(PPPProtocol *protocol)
{ {
// All protocols must go up. if(protocol->Flags() & PPP_NOT_IMPORTANT)
CloseEvent(); CloseEvent();
} }
@ -222,8 +237,8 @@ PPPStateMachine::DownEvent(PPPProtocol *protocol)
void void
PPPStateMachine::UpFailedEvent(PPPEncapsulator *encapsulator) PPPStateMachine::UpFailedEvent(PPPEncapsulator *encapsulator)
{ {
// All encapsulators must go up. if(encapsulator->Flags() & PPP_NOT_IMPORTANT)
CloseEvent(); CloseEvent();
} }
@ -337,9 +352,15 @@ PPPStateMachine::UpEvent()
NewState(PPP_CLOSED_STATE); NewState(PPP_CLOSED_STATE);
locker.UnlockNow(); locker.UnlockNow();
ThisLayerFinished(); ThisLayerFinished();
return;
} }
// TODO: handle server-up! // TODO: handle server-up!
NewState(PPP_REQ_SENT_STATE);
InitializeRestartCount();
locker.UnlockNow();
SendConfigureRequest();
break; break;
case PPP_STARTING_STATE: case PPP_STARTING_STATE:
@ -381,7 +402,7 @@ PPPStateMachine::DownEvent()
case PPP_STOPPED_STATE: case PPP_STOPPED_STATE:
// The RFC says we should reconnect, but our implementation // The RFC says we should reconnect, but our implementation
// will only do this if auto-redial is enabled (only clients). // will only do this if auto-redial is enabled (only clients).
NewStatus(PPP_STARTING_STATE); NewState(PPP_STARTING_STATE);
break; break;
case PPP_STOPPING_STATE: case PPP_STOPPING_STATE:
@ -389,7 +410,7 @@ PPPStateMachine::DownEvent()
case PPP_ACK_RCVD_STATE: case PPP_ACK_RCVD_STATE:
case PPP_ACK_SENT_STATE: case PPP_ACK_SENT_STATE:
case PPP_OPENED_STATE: case PPP_OPENED_STATE:
NewStatus(PPP_STARTING_STATE); NewState(PPP_STARTING_STATE);
break; break;
default: default:
@ -406,7 +427,9 @@ PPPStateMachine::DownEvent()
// maybe we need to redial // maybe we need to redial
if(State() == PPP_STARTING_STATE) { if(State() == PPP_STARTING_STATE) {
if(fAuthentiactionStatus == PPP_AUTHENTICATION_FAILED if(fAuthentiactionStatus == PPP_AUTHENTICATION_FAILED
|| fPeerAuthenticationStatus == PPP_AUTHENTICATION_FAILED) || fAuthenticationStatus == PPP_AUTHENTICATING
|| fPeerAuthenticationStatus == PPP_AUTHENTICATION_FAILED
|| fPeerAuthenticationStatus == PPP_AUTHENTICATING)
Interface()->Report(PPP_CONNECTION_REPORT, PPP_AUTHENTICATION_FAILED, Interface()->Report(PPP_CONNECTION_REPORT, PPP_AUTHENTICATION_FAILED,
NULL, 0); NULL, 0);
else else
@ -421,10 +444,14 @@ PPPStateMachine::DownEvent()
if(Interface()->DoesAutoRedial()) { if(Interface()->DoesAutoRedial()) {
// TODO: // TODO:
// Redial() // Redial()
} else } else if(!Interface()->DoesDialOnDemand())
Interface()->Delete(); Interface()->Delete();
} else } else {
Report(PPP_CONNECTION_REPORT, PPP_DOWN_SUCCESSFUL, NULL, 0); Interface()->Report(PPP_CONNECTION_REPORT, PPP_DOWN_SUCCESSFUL, NULL, 0);
if(!Interface()->DoesDialOnDemand())
Interface()->Delete();
}
} }
@ -436,11 +463,21 @@ PPPStateMachine::OpenEvent()
switch(State()) { switch(State()) {
case PPP_INITIAL_STATE: case PPP_INITIAL_STATE:
NewState(PPP_STARTING_STATE); if(!Interface()->Report(PPP_CONNECTION_REPORT, PPP_GOING_UP, NULL, 0))
return;
if(Interface()->Mode() == PPP_SERVER_MODE) {
NewPhase(PPP_ESTABLISHMENT_PHASE);
if(Interface()->Device())
Interface()->Device()->Listen();
} else
NewState(PPP_STARTING_STATE);
if(Interface()->IsMultilink() && !Interface()->Parent()) { if(Interface()->IsMultilink() && !Interface()->Parent()) {
NewPhase(PPP_ESTABLISHMENT_PHASE); NewPhase(PPP_ESTABLISHMENT_PHASE);
for(int32 i = 0; i < Interface()->CountChildren(); i++) for(int32 i = 0; i < Interface()->CountChildren(); i++)
Interface()->ChildAt(i)->Up(); Interface()->ChildAt(i)->StateMachine().OpenEvent();
} else { } else {
locker.UnlockNow(); locker.UnlockNow();
ThisLayerStarted(); ThisLayerStarted();
@ -473,12 +510,14 @@ PPPStateMachine::CloseEvent()
if(Interface()->IsMultilink() && !Interface()->Parent()) { if(Interface()->IsMultilink() && !Interface()->Parent()) {
NewState(PPP_INITIAL_STATE); NewState(PPP_INITIAL_STATE);
NewPhase(PPP_DOWN_PHASE);
if(Phase() != PPP_DOWN_PHASE)
NewPhase(PPP_TERMINATION_PHASE);
ThisLayerDown(); ThisLayerDown();
for(int32 i = 0; i < Interface()->CountChildren(); i++) for(int32 i = 0; i < Interface()->CountChildren(); i++)
Interface()->ChildAt(i)->Down(); Interface()->ChildAt(i)->StateMachine().CloseEvent();
return; return;
} }
@ -1328,7 +1367,7 @@ PPPStateMachine::BringHandlersUp()
if(BringPhaseUp() > 0) if(BringPhaseUp() > 0)
break; break;
fLock.Lock(); LockerHelper locker(fLock);
if(Phase() < PPP_AUTHENTICATION_PHASE) if(Phase() < PPP_AUTHENTICATION_PHASE)
return; return;
@ -1336,14 +1375,12 @@ PPPStateMachine::BringHandlersUp()
if(Interface()->Parent()) if(Interface()->Parent())
Interface()->Parent()->StateMachine().UpEvent(Interface()); Interface()->Parent()->StateMachine().UpEvent(Interface());
// TODO:
// Report(PPP_CONNECTION_REPORT, PPP_UP_SUCCESSFUL, NULL, 0);
if(Interface()->Ifnet()) if(Interface()->Ifnet())
Interface()->Ifnet()->if_flags |= IFF_RUNNING; Interface()->Ifnet()->if_flags |= IFF_RUNNING;
Interface()->Report(PPP_CONNECTION_REPORT, PPP_UP_SUCCESSFUL, NULL, 0);
} else } else
NewPhase(Phase() + 1); NewPhase(Phase() + 1);
fLock.Unlock();
} }
} }