diff --git a/src/tests/kits/net/ppp/headers/KPPPInterface.h b/src/tests/kits/net/ppp/headers/KPPPInterface.h index 964e178efd..07611507fe 100644 --- a/src/tests/kits/net/ppp/headers/KPPPInterface.h +++ b/src/tests/kits/net/ppp/headers/KPPPInterface.h @@ -7,6 +7,7 @@ #include "KPPPStateMachine.h" #include "KPPPLCP.h" +#include "KPPPReport.h" #include "List.h" #include "LockerHelper.h" @@ -27,6 +28,8 @@ class PPPInterface { PPPInterface(driver_settings *settings, PPPInterface *parent = NULL); ~PPPInterface(); + void Delete(); + status_t InitCheck() const; driver_settings* Settings() @@ -102,10 +105,12 @@ class PPPInterface { bool Down(); bool IsUp() const; -/* void EnableReports(PPP_REPORT type, thread_id thread, - int32 flags); - void DisableReports(PPP_REPORT type, thread_id thread); - bool DoesReport(PPP_REPORT type, thread_id thread); */ + void EnableReports(PPP_REPORT_TYPE type, port_id port, + int32 flags = PPP_NO_REPORT_FLAGS); + void DisableReports(PPP_REPORT_TYPE type, port_id port); + bool DoesReport(PPP_REPORT_TYPE type, port_id port); + bool Report(PPP_REPORT_TYPE type, int32 code, void *data, int32 length); + // returns false if reply was bad (or an error occured) bool LoadModules(const driver_settings *settings, int32 start, int32 count); @@ -126,8 +131,6 @@ class PPPInterface { // multilink methods void SetParent(PPPInterface *parent) { fParent = parent; } - -// void Report(PPP_REPORT type, int32 code, void *data, int32 length); private: driver_parameter *fSettings; @@ -153,8 +156,11 @@ class PPPInterface { PPPEncapsulator *fFirstEncapsulator; List fProtocols; List fModules; + List fReportRequests; - BLocker& fGeneralLock; + port_id fPort; + + BLocker& fLock; }; diff --git a/src/tests/kits/net/ppp/headers/KPPPReport.h b/src/tests/kits/net/ppp/headers/KPPPReport.h new file mode 100644 index 0000000000..9fcfcbe0d3 --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPReport.h @@ -0,0 +1,56 @@ +#ifndef _K_PPP_REPORT__H +#define _K_PPP_REPORT__H + +#define PPP_REPORT_DATA_LIMIT 128 + // how much optional data can be added to the report +#define PPP_REPORT_CODE '_3PR' + // the code field of read_port + + +// report flags +enum PPP_REPORT_FLAGS { + PPP_NO_REPORT_FLAGS = 0, + PPP_WAIT_FOR_REPLY = 0x1, + PPP_REMOVE_AFTER_REPORT = 0x2 +}; + +// report types +enum PPP_REPORT_TYPE { + PPP_DESTRUCTION_REPORT = 0, + // the interface is being destroyed (no code is needed) + PPP_CONNECTION_REPORT = 1 +}; + +// report codes (type-specific) +enum PPP_CONNECTION_REPORT_CODES { + PPP_UP_SUCCESSFUL = 1, + PPP_DOWN_SUCCESSFUL = 2, + PPP_UP_ABORTED = 3, + PPP_UP_FAILED = 4, + PPP_AUTHENTICATION_FAILED = 5, + PPP_CONNECTION_LOST = 6 +}; + +typedef struct ppp_report_packet { + port_id port; + int32 type; + int32 code; + uint8 len; + char data[PPP_REPORT_DATA_LIMIT]; +} ppp_report_packet; + + + +//*********** +// private +//*********** +#define PPP_REPORT_TIMEOUT 10000 + +typedef struct ppp_report_request { + port_id port; + int32 type; + int32 flags; +} ppp_report_request; + + +#endif diff --git a/src/tests/kits/net/ppp/src/KPPPInterface.cpp b/src/tests/kits/net/ppp/src/KPPPInterface.cpp index 56510114e1..34de90ff50 100644 --- a/src/tests/kits/net/ppp/src/KPPPInterface.cpp +++ b/src/tests/kits/net/ppp/src/KPPPInterface.cpp @@ -27,11 +27,13 @@ PPPInterface::PPPInterface(driver_settings *settings, PPPInterface *parent = NUL : fSettings(dup_driver_settings(settings)), StateMachine(*this), LCP(*this), fIfnet(NULL), fLinkMTU(1500), fAccessing(0), fChildrenCount(0), fDevice(NULL), fFirstEncapsulator(NULL), - fGeneralLock(StateMachine().Locker()) + fLock(StateMachine().Locker()) { if(get_module(PPP_MANAGER_MODULE_NAME, (module_info**) &fManager) != B_OK) fManager = NULL; + fPort = create_port(0, "PPP: reply port"); + // are we a multilink subinterface? if(parent && parent->IsMultilink()) { fParent = parent; @@ -75,11 +77,14 @@ PPPInterface::PPPInterface(driver_settings *settings, PPPInterface *parent = NUL PPPInterface::~PPPInterface() { + Report(PPP_DESTRUCTION_REPORT, 0, NULL, 0); + // tell all listeners that we are being destroyed + // TODO: // remove our iface, so that nobody will access it: // go down if up // unregister from ppp_manager - // delete children + // delete children/remove from parent // destroy and remove: // device // protocols @@ -89,13 +94,21 @@ PPPInterface::~PPPInterface() // put all modules (in fModules) put_module((module_info**) &fManager); + delete_port(fPort); +} + + +void +PPPInterface::Delete() +{ + fManager->delete_interface(this); } status_t PPPInterface::InitCheck() const { - if(!fSettings || !fManager) + if(!fSettings || !fManager || fPort < 0) return B_ERROR; // sub-interfaces should have a device @@ -421,7 +434,7 @@ PPPInterface::SetAutoRedial(bool autoredial = true) if(Mode() == PPP_CLIENT_MODE) return false; - LockerHelper locker(fGeneralLock); + LockerHelper locker(fLock); fAutoRedial = autoredial; } @@ -433,7 +446,7 @@ PPPInterface::SetDialOnDemand(bool dialondemand = true) if(Mode() != PPP_CLIENT_MODE) return false; - LockerHelper locker(fGeneralLock); + LockerHelper locker(fLock); fDialOnDemand = dialondemand; @@ -493,33 +506,111 @@ PPPInterface::Down() bool PPPInterface::IsUp() const { - LockerHelper locker(fGeneralLock); + LockerHelper locker(fLock); return StateMachine().Phase() == PPP_ESTABLISHED_PHASE; } -/* - void -PPPInterface::EnableReports(PPP_REPORT type, thread_id thread, - bool needsVerification = false) +PPPInterface::EnableReports(PPP_REPORT_TYPE type, port_id port, + int32 flags = PPP_NO_REPORT_FLAGS) { + LockerHelper locker(fLock); + + ppp_report_request request; + request.type = type; + request.port = port; + request.flags = flags; + + fReportRequests.AddItem(request); } void -PPPInterface::DisableReports(PPP_REPORT type, thread_id thread) +PPPInterface::DisableReports(PPP_REPORT_TYPE type, port_id port) { + LockerHelper locker(fLock); + + for(int32 i = 0; i < fReportRequests.CountItems(); i++) { + ppp_report_request& request = fReportRequests.ItemAt(i); + + if(request.port != port) + continue; + + if(report.type == type) + fReportRequest.RemoveItem(request); + } } bool -PPPInterface::Reports(PPP_REPORT type, thread_id thread) +PPPInterface::DoesReport(PPP_REPORT_TYPE type, port_id port) { + LockerHelper locker(fLock); + + for(int32 i = 0; i < fReportRequests.CountItems(); i++) { + ppp_report_request& request = fReportRequests.ItemAt(i); + + if(request.port == port && request.type == type) + return true; + } + + return false; } -*/ + +bool +PPPInterface::Report(PPP_REPORT_TYPE type, int32 code, void *data, int32 length) +{ + if(length > PPP_REPORT_DATA_LIMIT || fPort < 0) + return false; + + if(fReportRequests.CountItems() == 0) + return true; + + if(!data) + length = 0; + + LockerHelper locker(fLock); + + int32 code, query, result; + bool successful = true; + + report_packet report; + report.port = fPort; + report.type = type; + report.code = code; + report.length = length; + memcpy(report.data, data, length); + + for(int32 index = 0; index < fReportRequests.CountItems(); index++) { + ppp_report_request& request = fReportRequests.ItemAt(index); + + result = write_port_etc(request.port, PPP_REPORT_CODE, &report, + sizeof(report), B_TIMEOUT, PPP_REPORT_TIMEOUT); + + if(result == B_BAD_PORT_ID) { + fReportRequests.RemoveItem(request); + --index; + continue; + } else if(result == B_OK) { + if(request.flags & PPP_WAIT_FOR_REPLY) { + result = read_port_etc(fPort, &code, NULL, 0, + B_TIMEOUT, PPP_REPORT_TIMEOUT); + if(result == 0 && code != B_OK) + successful = false; + } + } + + if(request.flags & PPP_REMOVE_AFTER_REPORT) { + fReportRequests.RemoveItem(request); + --index; + } + } + + return successful; +} bool diff --git a/src/tests/kits/net/ppp/src/KPPPStateMachine.cpp b/src/tests/kits/net/ppp/src/KPPPStateMachine.cpp index 05b8f2d648..2f7ec0fa27 100644 --- a/src/tests/kits/net/ppp/src/KPPPStateMachine.cpp +++ b/src/tests/kits/net/ppp/src/KPPPStateMachine.cpp @@ -293,7 +293,7 @@ PPPStateMachine::UpFailedEvent() switch(State()) { case PPP_STARTING_STATE: - // we must have called TLS() which sets establishment phase + // TLSNotify() sets establishment phase if(Phase() != PPP_ESTABLISHMENT_PHASE) { // there must be a BUG in the device add-on or someone is trying to // fool us (UpEvent() is public) as we did not request the device @@ -303,9 +303,8 @@ PPPStateMachine::UpFailedEvent() break; } - // TODO: - // report that up failed - // Report(PPP_CONNECTION_REPORT, PPP_UP_FAILED, NULL, 0); + Interface()->Report(PPP_CONNECTION_REPORT, PPP_UP_FAILED, NULL, 0); + if(Interface()->Parent()) Interface()->Parent()->StateMachine().UpFailedEvent(Interface()); break; @@ -373,8 +372,6 @@ PPPStateMachine::DownEvent() { LockerHelper locker(fLock); - NewPhase(PPP_DOWN_PHASE); - switch(State()) { case PPP_CLOSED_STATE: case PPP_CLOSING_STATE: @@ -385,40 +382,14 @@ PPPStateMachine::DownEvent() // The RFC says we should reconnect, but our implementation // will only do this if auto-redial is enabled (only clients). NewStatus(PPP_STARTING_STATE); - - // TODO: - // report that we lost the connection - // if fAuthStatus == FAILED || fPeerAuthStatus == FAILED - // Report(PPP_CONNECTION_REPORT, PPP_AUTH_FAILED, NULL, 0); - // else - // Report(PPP_CONNECTION_REPORT, PPP_CONNECTION_LOST, NULL, 0); break; case PPP_STOPPING_STATE: - NewStatus(PPP_STARTING_STATE); - - // TODO: - // report that we lost the connection - // Report(PPP_CONNECTION_REPORT, PPP_CONNECTION_LOST, NULL, 0); - break; - case PPP_REQ_SENT_STATE: case PPP_ACK_RCVD_STATE: case PPP_ACK_SENT_STATE: - NewStatus(PPP_STARTING_STATE); - - // TODO: - // report that we lost the connection - // Report(PPP_CONNECTION_REPORT, PPP_CONNECTION_LOST, NULL, 0); - break; - case PPP_OPENED_STATE: - // tld/1 NewStatus(PPP_STARTING_STATE); - - // TODO: - // report that we lost the connection - // Report(PPP_CONNECTION_REPORT, PPP_CONNECTION_LOST, NULL, 0); break; default: @@ -430,19 +401,30 @@ PPPStateMachine::DownEvent() // DownEncapsulators(); // ResetOptionHandlers(); + NewPhase(PPP_DOWN_PHASE); + // maybe we need to redial if(State() == PPP_STARTING_STATE) { + if(fAuthentiactionStatus == PPP_AUTHENTICATION_FAILED + || fPeerAuthenticationStatus == PPP_AUTHENTICATION_FAILED) + Interface()->Report(PPP_CONNECTION_REPORT, PPP_AUTHENTICATION_FAILED, + NULL, 0); + else + Interface()->Report(PPP_CONNECTION_REPORT, PPP_CONNECTION_LOST, + NULL, 0); + + if(Interface()->Parent()) + Interface()->Parent()->StateMachine().UpFailedEvent(Interface()); + + NewState(PPP_INITIAL_STATE); + if(Interface()->DoesAutoRedial()) { - NewState(PPP_INITIAL_STATE); // TODO: - // redial using a new thread (maybe interface manager will help us) - } else { - if(Interface()->Parent()) - Interface()->Parent()->StateMachine().UpFailedEvent(Interface()); - // TODO: - // we must delete our interface - } - } + // Redial() + } else + Interface()->Delete(); + } else + Report(PPP_CONNECTION_REPORT, PPP_DOWN_SUCCESSFUL, NULL, 0); } @@ -674,6 +656,8 @@ PPPStateMachine::RCRBadEvent(mbuf *nak, mbuf *reject) case PPP_OPENED_STATE: NewState(PPP_REQ_SENT_STATE); + NewPhase(PPP_ESTABLISHMENT_PHASE); + // tell handlers that we are reconfiguring locker.UnlockNow(); ThisLayerDown(); SendConfigureRequest(); @@ -749,6 +733,8 @@ PPPStateMachine::RCAEvent(mbuf *packet) case PPP_OPENED_STATE: NewState(PPP_REQ_SENT_STATE); + NewPhase(PPP_ESTABLISHMENT_PHASE); + // tell handlers that we are reconfiguring locker.UnlockNow(); ThisLayerDown(); SendConfigureRequest(); @@ -808,6 +794,8 @@ PPPStateMachine::RCNEvent(mbuf *packet) case PPP_OPENED_STATE: NewState(PPP_REQ_SENT_STATE); + NewPhase(PPP_ESTABLISHMENT_PHASE); + // tell handlers that we are reconfiguring locker.UnlockNow(); ThisLayerDown(); SendConfigureRequest(); @@ -835,12 +823,16 @@ PPPStateMachine::RTREvent(mbuf *packet) case PPP_ACK_RCVD_STATE: case PPP_ACK_SENT_STATE: NewState(PPP_REQ_SENT_STATE); + NewPhase(PPP_TERMINATION_PHASE); + // tell handlers that we are terminating locker.UnlockNow(); SendTerminateAck(packet); break; case PPP_OPENED_STATE: NewState(PPP_STOPPING_STATE); + NewPhase(PPP_TERMINATION_PHASE); + // tell handlers that we are terminating ZeroRestartCount(); locker.UnlockNow(); ThisLayerDown(); @@ -848,6 +840,8 @@ PPPStateMachine::RTREvent(mbuf *packet) break; default: + NewPhase(PPP_TERMINATION_PHASE); + // tell handlers that we are terminating locker.UnlockNow(); SendTerminateAck(packet); } @@ -1155,7 +1149,15 @@ PPPStateMachine::ThisLayerUp() // We begin with authentication phase and wait until each phase is done. // We stop when we reach established phase. + + // Do not forget to check if we are going down. + if(Phase() != PPP_ESTABLISHMENT_PHASE) + return; + NewPhase(PPP_AUTHENTICATION_PHASE); + + locker.UnlockNow(); + BringHandlersUp(); } @@ -1166,8 +1168,8 @@ PPPStateMachine::ThisLayerDown() // TODO: // DownProtocols(); // DownEncapsulators(); - // If there are protocols/encapsulators with PPP_DOWN_NEEDED flag - // wait until they report a DownEvent() (or until all of them are down). + + // PPPProtocol/Encapsulator::Down() should block if needed. } @@ -1182,10 +1184,6 @@ PPPStateMachine::ThisLayerStarted() void PPPStateMachine::ThisLayerFinished() { - // TODO: - // DownProtocols(); - // DownEncapsulators(); - if(Interface()->Device()) Interface()->Device()->Down(); } @@ -1326,11 +1324,15 @@ PPPStateMachine::SendEchoReply(mbuf *request) void PPPStateMachine::BringHandlersUp() { - while(Phase() <= PPP_ESTABLISHED_PHASE) { + while(Phase() <= PPP_ESTABLISHED_PHASE && Phase() >= PPP_AUTHENTICATION_PHASE) { if(BringPhaseUp() > 0) break; - if(Phase() == PPP_ESTABLISHED_PHASE) { + fLock.Lock(); + + if(Phase() < PPP_AUTHENTICATION_PHASE) + return; + else if(Phase() == PPP_ESTABLISHED_PHASE) { if(Interface()->Parent()) Interface()->Parent()->StateMachine().UpEvent(Interface()); @@ -1340,6 +1342,8 @@ PPPStateMachine::BringHandlersUp() Interface()->Ifnet()->if_flags |= IFF_RUNNING; } else NewPhase(Phase() + 1); + + fLock.Unlock(); } } @@ -1348,6 +1352,11 @@ PPPStateMachine::BringHandlersUp() uint32 PPPStateMachine::BringPhaseUp() { + LockerHelper locker(fLock); + + if(Phase() < PPP_AUTHENTICATION_PHASE) + return 0; + uint32 count = 0; PPPProtocol *protocol_handler; PPPEncapsulator *encapsulator_handler = Interface()->FirstEncapsulator();