diff --git a/src/tests/kits/net/ppp/headers/AccessHelper.h b/src/tests/kits/net/ppp/headers/AccessHelper.h new file mode 100644 index 0000000000..4c25068d3e --- /dev/null +++ b/src/tests/kits/net/ppp/headers/AccessHelper.h @@ -0,0 +1,36 @@ +/* + * AccessHelper.h + * + * The AccessHelper class automatically increases the given variable by + * one on construction and decreases it by one on destruction. If a NULL + * pointer is given, it will do nothing. + * + */ + + +#ifndef _ACCESS_HELPER__H +#define _ACCESS_HELPER__H + +#include +#include + + +class AccessHelper { + public: + AccessHelper(vint32 *access) : fAccess(access) + { + if(fAccess) + atomic_add(fAccess, 1); + } + + ~AccessHelper() + { + if(fAccess) + atomic_add(fAccess, -1); + } + + private: + vint32 *fAccess; +}; + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPConfigurePacket.h b/src/tests/kits/net/ppp/headers/KPPPConfigurePacket.h new file mode 100644 index 0000000000..b8dbc38fbe --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPConfigurePacket.h @@ -0,0 +1,36 @@ +#ifndef _K_PPP_CONFIGURE_PACKET__H +#define _K_PPP_CONFIGURE_PACKET__H + +#include + + +typedef struct configure_item { + void *data; + int32 len; + uint8 type; +} configure_item; + + +class PPPConfigurePacket { + public: + PPPConfigurePacket(uint8 type); + PPPConfigurePacket(mbuf *data); + ~PPPConfigurePacket(); + + bool SetType(uint8 type); + uint8 Type() const + { return fType; } + + void AddItem(configure_item *item); + bool RemoveItem(configure_item *item); + int32 CountItems() const; + configure_item *ItemAt(int32 index) const; + + mbuf *ToMbuf() const; + + private: + uint8 fType; +}; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPDefs.h b/src/tests/kits/net/ppp/headers/KPPPDefs.h new file mode 100644 index 0000000000..b42e154fe5 --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPDefs.h @@ -0,0 +1,185 @@ +#ifndef _K_PPP_DEFS__H +#define _K_PPP_DEFS__H + +#include + + +// settings keys +#define PPP_MODE_KEY "Mode" +#define PPP_DIAL_ON_DEMAND_KEY "DialOnDemand" +#define PPP_AUTO_REDIAL_KEY "AutoRedial" +#define PPP_LOAD_MODULE_KEY "LoadModule" +#define PPP_PROTOCOL_KEY "Protocol" +#define PPP_DEVICE_KEY "Device" +#define PPP_AUTHENTICATOR_KEY "Authenticator" +#define PPP_PEER_AUTHENTICATOR_KEY "Peer-Authenticator" + +// settings values +#define PPP_CLIENT_MODE_VALUE "Client" +#define PPP_SERVER_MODE_VALUE "Server" + +// path defines +#define PPP_MODULES_PATH "network/ppp-modules" + +// built-in protocols +// #define PPP_LCP_PROTOCOL 0xC021 + + +#define PPP_ERROR_BASE B_ERRORS_END + +// return values for Receive methods in addition to B_ERROR and B_OK +enum { + // B_ERROR means that the packet is corrupted + // B_OK means the packet was handled correctly + + // return values for PPPProtocol and PPPEncapsulator + PPP_UNHANDLED = PPP_ERROR_BASE, + // The packet does not belong to this handler. + // Do not delete the packet when you return this! + + // return values of PPPInterface::Receive() + PPP_DISCARDED, + // packet was silently discarded + PPP_REJECTED, + // a protocol-reject +}; + +// module key types (used when loading a module) +enum { + PPP_LOAD_MODULE_TYPE, + PPP_DEVICE_TYPE, + PPP_PROTOCOL_TYPE, + PPP_AUTHENTICATOR_TYPE, + PPP_PEER_AUTHENTICATOR_TYPE +}; + +// protocol and encapsulator flags +enum { + PPP_NO_FLAGS = 0x00, + PPP_ALWAYS_ALLOWED = 0x01, + // protocol may send/receive while we are authenticating + 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) +}; + +// phase when the protocol is brought up +enum PPP_PHASE { + // the following may be used by protocols + PPP_AUTHENTICATION_PHASE = 15, + PPP_NCP_PHASE = 20, + PPP_ESTABLISHED_PHASE = 25, + // only use PPP_ESTABLISHED_PHASE if + // you want to activate this protocol after + // the normal protocols like IP (i.e., IPCP) + + // the following must not be used by protocols! + PPP_CTOR_DTOR_PHASE = -1, + // set on construction/destruction of the interface + PPP_DOWN_PHASE = 0, + PPP_TERMINATION_PHASE = 1, + // this is the selected phase when we are GOING down + PPP_ESTABLISHMENT_PHASE = 2 + // in this phase some protocols (with PPP_ALWAYS_ALLOWED + // flag set) may be used +}; + +// this defines the order in which the packets get encapsulated +enum PPP_ENCAPSULATION_LEVEL { + PPP_MULTILINK_LEVEL = 0, + PPP_ENCRYPTION_LEVEL = 5, + PPP_COMPRESSION_LEVEL = 10 +}; + +// we can be a ppp client or a ppp server interface +enum PPP_MODE { + PPP_CLIENT_MODE = 0, + PPP_SERVER_MODE +}; + +// report types +enum PPP_REPORT { + PPP_CONNECTION_REPORT = 0x01, + PPP_ERROR_REPORT = 0x02, +}; + +// authentication status +enum PPP_AUTHENTICATION_STATUS { + PPP_AUTHENTICATION_FAILED = -1, + PPP_NOT_AUTHENTICATED = 0, + PPP_AUTHENTICATION_SUCCESSFUL = 1, + PPP_AUTHENTICATING = 0xFF +}; + +// PPP states as defined in RFC 1661 +enum PPP_STATE { + PPP_INITIAL_STATE, + PPP_STARTING_STATE, + PPP_CLOSED_STATE, + PPP_STOPPED_STATE, + PPP_CLOSING_STATE, + PPP_STOPPING_STATE, + PPP_REQ_SENT_STATE, + PPP_ACK_RCVD_STATE, + PPP_ACK_SENT_STATE, + PPP_OPENED_STATE +}; + +// PPP actions as defined in RFC 1661 +enum PPP_ACTION { + PPP_ILLEGAL_EVENT_ACTION, + PPP_THIS_LAYER_UP_ACTION, + PPP_THIS_LAYER_DOWN_ACTION, + PPP_THIS_LAYER_STARTED_ACTION, + PPP_THIS_LAYER_FINISHED_ACTION, + PPP_INIT_RESTART_COUNT_ACTION, + PPP_ZERO_RESTART_COUNT_ACTION, + PPP_SEND_CONF_REQ_ACTION, + PPP_SEND_CONF_ACK_ACTION, + PPP_SEND_CONF_NAK_ACTION, + PPP_SEND_TERM_REQ_ACTION, + PPP_SEND_TERM_ACK_ACTION, + PPP_SEND_CODE_REJ_ACTION, + PPP_SEND_ECHO_REPLY_ACTION +}; + +// PPP events as defined in RFC 1661 (with one exception: PPP_UP_FAILED_EVENT) +enum PPP_EVENT { + PPP_UP_FAILED_EVENT, + PPP_UP_EVENT, + PPP_DOWN_EVENT, + PPP_OPEN_EVENT, + PPP_CLOSE_EVENT, + PPP_TO_GOOD_EVENT, + PPP_TO_BAD_EVENT, + PPP_RCR_GOOD_EVENT, + PPP_RCR_BAD_EVENT, + PPP_RCA_EVENT, + PPP_RCN_EVENT, + PPP_RTR_EVENT, + PPP_RTA_EVENT, + PPP_RUC_EVENT, + PPP_RXJ_GOOD_EVENT, + PPP_RXJ_BAD_EVENT, + PPP_RXR_EVENT +}; + +// LCP protocol types as defined in RFC 1661 +// ToDo: add LCP extensions +enum PPP_LCP_TYPE { + PPP_CONFIGURE_REQUEST = 1, + PPP_CONFIGURE_ACK = 2, + PPP_CONFIGURE_NAK = 3, + PPP_CONFIGURE_REJECT = 4, + PPP_TERMINATE_REQUEST = 5, + PPP_TERMINATE_ACK = 6, + PPP_CODE_REJECT = 7, + PPP_PROTOCOL_REJECT = 8, + PPP_ECHO_REQUEST = 9, + PPP_ECHO_REPLY = 10, + PPP_DISCARD_REQUEST = 11 +}; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPDevice.h b/src/tests/kits/net/ppp/headers/KPPPDevice.h new file mode 100644 index 0000000000..a2618f2578 --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPDevice.h @@ -0,0 +1,56 @@ +#ifndef _K_PPP_DEVICE__H +#define _K_PPP_DEVICE__H + +#include "KPPPInterface.h" + + +class PPPDevice { + public: + PPPDevice(const char *fName, PPPInterface *interface, driver_parameter *settings); + virtual ~PPPDevice(); + + virtual status_t InitCheck() const = 0; + + const char *Name() const + { return fName; } + + PPPInterface *Interface() const + { return fInterface; } + driver_parameter *Settings() + { return fSettings; } + + virtual status_t Control(uint32 op, void *data, size_t length); + + virtual bool SetMTU(uint32 mtu) = 0; + uint32 MTU() const + { return fMTU; } + virtual bool LockMTU(); + virtual bool UnlockMTU(); + virtual uint32 PreferredMTU() const = 0; + + virtual void Up() = 0; + virtual void Down() = 0; + virtual void Listen() = 0; + bool IsUp() const + { return fIsUp; } + + virtual status_t Send(mbuf *packet) = 0; + + protected: + void SetUp(bool isUp); + // report up/down events + + protected: + bool fIsUp; + + private: + char *fName; + PPPInterface *fInterface; + driver_parameter *fSettings; + + uint32 fMTU; + int32 fMTULock; +}; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPEncapsulator.h b/src/tests/kits/net/ppp/headers/KPPPEncapsulator.h new file mode 100644 index 0000000000..5d285a9b1c --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPEncapsulator.h @@ -0,0 +1,86 @@ +#ifndef _K_PPP_ENCAPSULATOR__H +#define _K_PPP_ENCAPSULATOR__H + +#include "KPPPInterface.h" + + +class PPPEncapsulator { + public: + PPPEncapsulator(const char *name, PPP_ENCAPSULATION_LEVEL level, + uint16 protocol, int32 addressFamily, uint32 overhead, + PPPInterface *interface, driver_parameter *settings, + int32 flags = PPP_NO_FLAGS); + virtual ~PPPEncapsulator(); + + virtual status_t InitCheck() const = 0; + + void SetEnabled(bool enabled = true); + bool IsEnabled() const + { return fEnabled; } + + const char *Name() const + { return fName; } + + PPP_ENCAPSULATION_LEVEL Level() const + { return fLevel; } + uint32 Overhead() const + { return fOverhead; } + + PPPInterface *Interface() const + { return fInterface; } + driver_parameter *Settings() + { return fSettings; } + + uint16 Protocol() const + { return fProtocol; } + int32 AddressFamily() const + { return fAddressFamily; } + // negative values and values > 0xFF are ignored + int32 Flags() const + { return fFlags; } + + virtual status_t Control(uint32 op, void *data, size_t length); + + void SetNext(PPPEncapsulator *next) + { fNext = next; } + PPPEncapsulator *Next() const + { return fNext; } + + virtual bool Up() = 0; + virtual bool Down() = 0; + virtual bool Reset() = 0; + // reset to initial (down) state without sending something + bool IsUp() const + { return fIsUp; } + + virtual status_t Send(mbuf *packet, uint16 protocol) = 0; + virtual status_t Receive(mbuf *packet, uint16 protocol) = 0; + + status_t SendToNext(mbuf *packet, uint16 protocol); + // this will send your packet to the next (up) encapsulator + // if there is no next encapsulator (==NULL), it will + // call the interface's SendToDevice function + + protected: + void SetUp(bool isUp); + // report up/down events + + protected: + uint32 fOverhead; + + private: + char *fName; + PPP_ENCAPSULATION_LEVEL fLevel; + PPPInterface *fInterface; + driver_parameter *fSettings; + uint16 fProtocol; + int32 fAddressFamily, fFlags; + + PPPEncapsulator *fNext; + + bool fIsUp; + bool fEnabled; +}: + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPFSM.h b/src/tests/kits/net/ppp/headers/KPPPFSM.h new file mode 100644 index 0000000000..414fc3d1ef --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPFSM.h @@ -0,0 +1,108 @@ +#ifndef _K_PPP_FSM__H +#define _K_PPP_FSM__H + +#include "KPPPLCP.h" + +#include "Locker.h" + + +class PPPFSM { + friend class PPPInterface; + friend class PPPLCP; + + private: + // may only be constructed/destructed by PPPInterface + PPPFSM(PPPInterface &interface); + ~PPPFSM(); + + public: + PPPInterface *Interface() const + { return fInterface; } + + PPP_STATE State() const + { return fState; } + PPP_PHASE Phase() const + { return fPhase; } + + // public events + void AuthenticationRequested(); + void AuthenticationAccepted(const char *name); + void AuthenticationDenied(const char *name); + const char *AuthenticationName() const; + // returns NULL if not authenticated + PPP_AUTHENTICATION_STATUS AuthenticationStatus() const + { return fAuthenticationStatus; } + + void PeerAuthenticationRequested(); + void PeerAuthenticationAccepted(const char *name); + void PeerAuthenticationDenied(const char *name); + const char *PeerAuthenticationName() const; + // returns NULL if not authenticated + PPP_AUTHENTICATION_STATUS PeerAuthenticationStatus() const + { return fPeerAuthenticationStatus; } + + bool TLSNotify(); + bool TLFNotify(); + void UpFailedEvent(); + void UpEvent(); + void DownEvent(); + + private: + BLocker &Locker() + { return fLock; } + void LeaveConstructionPhase(); + void EnterDestructionPhase(); + + // private FSM methods + void NewState(PPP_STATE next); + + // private events + void OpenEvent(); + void CloseEvent(); + void TOGoodEvent(); + void TOBadEvent(); + void RCRGoodEvent(PPPConfigurePacket *packet); + void RCRBadEvent(PPPConfigurePacket *packet); + void RCAEvent(PPPConfigurePacket *packet); + void RCNEvent(PPPConfigurePacket *packet); + void RTREvent(); + void RTAEvent(); + void RUCEvent(); + void RJXGoodEvent(); + void RJXBadEvent(); + void RXREvent(); + + // actions + void IllegalEvent(PPP_EVENT event); + void ThisLayerUp(); + void ThisLayerDown(); + void ThisLayerStarted(); + void ThisLayerFinished(); + void InitializeRestartCount(); + void ZeroRestartCount(); + void SendConfigureRequest(); + void SendConfigureAck(PPPConfigurePacket *packet); + + void SendConfigureNak(PPPConfigurePacket *packet); + // is this needed? + + void SendTerminateRequest(); + void SendTerminateAck(); + void SendCodeReject(); + void SendEchoReply(); + + private: + PPPInterface *fInterface; + + PPP_PHASE fPhase; + PPP_STATE fState; + + PPP_AUTHENTICATION_STATUS fAuthenticationStatus, + fPeerAuthenticationStatus; + int32 fAuthenticatorIndex, fPeerAuthenticatorIndex; + + BLocker fLock; +}; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPInterface.h b/src/tests/kits/net/ppp/headers/KPPPInterface.h new file mode 100644 index 0000000000..b024e3e00b --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPInterface.h @@ -0,0 +1,142 @@ +#ifndef _K_PPP_INTERFACE__H +#define _K_PPP_INTERFACE__H + +#include + +#include "KPPPDefs.h" + +#include "KPPPFSM.h" +#include "KPPPLCP.h" + +#include "List.h" +#include "LockerHelper.h" + +class PPPAuthenticator; +class PPPDevice; +class PPPEncapsulator; +class PPPOptionHandler; +class PPPProtocol; + + +class PPPInterface { + public: + PPPInterface(driver_settings *settings); + ~PPPInterface(); + + status_t InitCheck() const; + + driver_settings* Settings() + { return fSettings; } + + PPPFSM &FSM() const + { return fFSM; } + + bool RegisterInterface(); + // adds us to the manager module and + // saves the returned ifnet structure + bool UnregisterInterface(); + ifnet *Ifnet() const + { return fIfnet; } + + void SetLinkMTU(uint32 linkMTU); + uint32 LinkMTU() const + { return fLinkMTU; } + // this is the smallest MTU that we and the peer have + uint32 MRU() const + { return fMRU; } + + status_t Control(uint32 op, void *data, size_t length); + + bool SetDevice(PPPDevice *device); + + bool AddProtocol(PPPProtocol *protocol); + bool RemoveProtocol(PPPProtocol *protocol); + int32 CountProtocols() const + { return fProtocols.CountItems(); } + PPPProtocol *ProtocolAt(int32 index) const; + PPPProtocol *ProtocolFor(uint16 protocol, int32 start = 0) const; + int32 IndexOfProtocol(const PPPProtocol *protocol) const + { return fProtocols.IndexOf(protocol); } + + bool AddEncapsulator(PPPEncapsulator *encapsulator); + bool RemoveEncapsulator(PPPEncapsulator *encapsulator); + PPPEncapsulator *FirstEncapsulator() const + { return fFirstEncapsulator; } + PPPEncapsulator *EncapsulatorFor(uint16 protocol, + PPPEncapsulator start = NULL) const; + + bool AddOptionHandler(PPPOptionHandler *handler); + bool RemoveOptionHandler(PPPOptionHandler *handler); + int32 CountOptionHandlers() const + { return fOptionHandlers.CountItems(); } + PPPOptionHandler *OptionHandlerAt(int32 index) const; + + void SetAutoRedial(bool autoredial = true); + bool DoesAutoRedial() const + { return fAutoRedial; } + + void SetDialOnDemand(bool dialondemand = true); + bool DoesDialOnDemand() const + { return fDialOnDemand; } + + PPP_MODE Mode() const + { return fMode; } + // client or server mode? + PPP_STATE State() const + { return FSM().State(); } + PPP_PHASE Phase() const + { return FSM().Phase(); } + + bool Up(); + // in server mode Up() listens for an incoming connection + bool Down(); + bool IsUp() const; + +/* void EnableReports(PPP_REPORT type, thread_id thread, + PPP_REPORT_FLAGS flags); + void DisableReports(PPP_REPORT type, thread_id thread); + bool DoesReport(PPP_REPORT type, thread_id thread); */ + + bool LoadModules(const driver_settings *settings, + int32 start, int32 count); + bool LoadModule(const char *name, const driver_parameter *parameter); + + status_t Send(mbuf *packet, uint16 protocol); + status_t Receive(mbuf *packet, uint16 protocol); + + status_t SendToDevice(mbuf *packet, uint16 protocol); + status_t ReceiveFromDevice(mbuf *packet); + + private: + PPPLCP &LCP() const + { return fLCP; } + void CalculateMRU(); + +// void Report(PPP_REPORT type, int32 code, void *data, int32 length); + + private: + driver_parameter *fSettings; + PPPFSM fFSM; + PPPLCP fLCP; + ifnet *fIfnet; + + uint32 fLinkMTU, fMRU, fHeaderLength; + + bool fAutoRedial, fDialOnDemand; + + vint32 fAccesing; + + PPP_MODE fMode; + + PPPDevice *fDevice; + PPPEncapsulator *fFirstEncapsulator; + + List fProtocols; + List fOptionHandlers; + List fModules; + + BLocker &fGeneralLock; +}; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPLCP.h b/src/tests/kits/net/ppp/headers/KPPPLCP.h new file mode 100644 index 0000000000..03eb179a84 --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPLCP.h @@ -0,0 +1,23 @@ +#ifndef _K_PPP_LCP__H +#define _K_PPP_LCP__H + +#include "KPPPProtocol.h" + + +class PPPLCP : public PPPProtocol { + friend class PPPInterface; + + private: + // may only be constructed/destructed by PPPInterface + PPPLCP(PPPInterface &interface); + ~PPPLCP(); + + public: + + + private: + +}; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPManager.h b/src/tests/kits/net/ppp/headers/KPPPManager.h new file mode 100644 index 0000000000..a3a825d0a2 --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPManager.h @@ -0,0 +1,30 @@ +#ifndef _K_PPP_MANAGER__H +#define _K_PPP_MANAGER__H + +#include + + +#define PPP_MANAGER_MODULE_NAME "network/interfaces/ppp" + + +typedef struct ppp_manager_info { + kernel_net_module_info knminfo; + + // when you want to iterate through interfaces you should use locking + void (*lock)(); + void (*unlock)(); + + ifnet* (*add_interface)(PPPInterface *interface); + bool (*remove_interface)(PPPInterface *interface); + + int32 (*count_interfaces)(int32 index); + + PPPInterface *(*get_interface_at)(int32 index); + void (*put_interface)(PPPInterface *interface); + + void (*delete_interface)(PPPInterface *interface); + // this deletes the interface when it is not needed anymore +} ppp_manager; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPModule.h b/src/tests/kits/net/ppp/headers/KPPPModule.h new file mode 100644 index 0000000000..81c62f4dd5 --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPModule.h @@ -0,0 +1,16 @@ +#ifndef _K_PPP_MODULE__H +#define _K_PPP_MODULE__H + +#include + +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 *interface, driver_parameter *settings, int32 type); +} ppp_module_info; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPOptionHandler.h b/src/tests/kits/net/ppp/headers/KPPPOptionHandler.h new file mode 100644 index 0000000000..dd18e75d5a --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPOptionHandler.h @@ -0,0 +1,55 @@ +#ifndef _K_PPP_OPTION_HANDLER__H +#define _K_PPP_OPTION_HANDLER__H + +#include "KPPPConfigurePacket.h" +#include "KPPPInterface.h" + + +class PPPOptionHandler { + public: + PPPOptionHandler(const char *name, PPPInterface *interface, + driver_parameter *settings); + virtual ~PPPOptionHandler(); + + virtual status_t InitCheck() = 0; + + void SetEnabled(bool enabled = true); + bool IsEnabled() const + { return fEnabled; } + + const char *Name() const + { return fName; } + + PPPInterface *Interface() const + { return fInterface; } + driver_parameter *Settings() + { return fSettings; } + + virtual void Reset() = 0; + // e.g.: remove list of rejected values + + // we want to send a configure request or we received a reply + virtual bool AddToRequest(PPPConfigurePacket *request) = 0; + virtual void ParseNak(const PPPConfigurePacket *nak) = 0; + // create next request based on these and previous values + virtual void ParseReject(const PPPConfigurePacket *reject) = 0; + // create next request based on these and previous values + virtual void ParseAck(const PPPConfigurePacket *ack) = 0; + // this is called for all handlers + + // peer sent configure request + virtual bool ParseConfigureRequest(const PPPConfigurePacket *request, + int32 item, PPPConfigurePacket *nak, PPPConfigurePacket *reject) = 0; + // item may be behind the last item which means we can add + // additional values + + private: + const char *fName; + PPPInterface *fInterface; + driver_parameters *fSettings; + + bool fEnabled; +}; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/KPPPProtocol.h b/src/tests/kits/net/ppp/headers/KPPPProtocol.h new file mode 100644 index 0000000000..d456056df6 --- /dev/null +++ b/src/tests/kits/net/ppp/headers/KPPPProtocol.h @@ -0,0 +1,66 @@ +#ifndef _K_PPP_PROTOCOL__H +#define _K_PPP_PROTOCOL__H + +#include "KPPPInterface.h" + + +class PPPProtocol { + public: + PPPProtocol(const char *name, PPP_PHASE phase, uint16 protocol, + int32 addressFamily, PPPInterface *interface, + driver_parameter *settings, int32 flags = PPP_NO_FLAGS); + virtual ~PPPProtocol(); + + virtual status_t InitCheck() const = 0; + + void SetEnabled(bool enabled = true); + bool IsEnabled() const + { return fEnabled; } + + const char *Name() const + { return fName; } + + PPP_PHASE Phase() const + { return fPhase; } + + driver_parameter *Settings() + { return fSettings; } + + uint16 Protocol() const + { return fProtocol; } + int32 AddressFamily() const + { return fAddressFamily; } + // negative values and values > 0xFF are ignored + int32 Flags() const + { return fFlags; } + + virtual status_t Control(uint32 op, void *data, size_t length); + + virtual bool Up() = 0; + virtual bool Down() = 0; + virtual bool Reset() = 0; + // reset to initial (down) state without sending something + bool IsUp() const + { return fIsUp; } + + virtual status_t Send(mbuf *packet) = 0; + virtual status_t Receive(mbuf *packet) = 0; + + protected: + void SetUp(bool isUp); + // report up/down events + + private: + char *name; + PPP_PHASE fPhase; + uint16 fProtocol; + int32 fAddressFamily, fFlags; + PPPInterface fInterface; + driver_parameter fSettings; + + bool fIsUp; + bool fEnabled; +}; + + +#endif diff --git a/src/tests/kits/net/ppp/headers/List.h b/src/tests/kits/net/ppp/headers/List.h new file mode 100644 index 0000000000..21aeb87533 --- /dev/null +++ b/src/tests/kits/net/ppp/headers/List.h @@ -0,0 +1,385 @@ +// List.h +// +// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// Except as contained in this notice, the name of a copyright holder shall +// not be used in advertising or otherwise to promote the sale, use or other +// dealings in this Software without prior written authorization of the +// copyright holder. + +#ifndef LIST_H +#define LIST_H + +#include +#include +#include + +#include + +template +class DefaultDefaultItemCreator { +public: + static inline ITEM GetItem() { return ITEM(0); } +}; + +/*! + \class List + \brief A generic list implementation. +*/ +template > +class List { +public: + typedef ITEM item_t; + typedef List list_t; + +private: + static item_t sDefaultItem; + static const size_t kDefaultChunkSize = 10; + static const size_t kMaximalChunkSize = 1024 * 1024; + +public: + List(size_t chunkSize = kDefaultChunkSize); + ~List(); + + inline const item_t &GetDefaultItem() const; + inline item_t &GetDefaultItem(); + + bool AddItem(const item_t &item, int32 index); + bool AddItem(const item_t &item); +// bool AddList(list_t *list, int32 index); +// bool AddList(list_t *list); + + bool RemoveItem(const item_t &item); + bool RemoveItem(int32 index); + + bool ReplaceItem(int32 index, const item_t &item); + + bool MoveItem(int32 oldIndex, int32 newIndex); + + void MakeEmpty(); + + int32 CountItems() const; + bool IsEmpty() const; + const item_t &ItemAt(int32 index) const; + item_t &ItemAt(int32 index); + const item_t *Items() const; + int32 IndexOf(const item_t &item) const; + bool HasItem(const item_t &item) const; + + // debugging + int32 GetCapacity() const { return fCapacity; } + +private: + inline static void _MoveItems(item_t* items, int32 offset, int32 count); + bool _Resize(size_t count); + +private: + size_t fCapacity; + size_t fChunkSize; + int32 fItemCount; + item_t *fItems; +}; + +// sDefaultItem +template +List::item_t + List::sDefaultItem( + DEFAULT_ITEM_SUPPLIER::GetItem()); + +// constructor +template +List::List(size_t chunkSize) + : fCapacity(0), + fChunkSize(chunkSize), + fItemCount(0), + fItems(NULL) +{ + if (fChunkSize == 0 || fChunkSize > kMaximalChunkSize) + fChunkSize = kDefaultChunkSize; + _Resize(0); +} + +// destructor +template +List::~List() +{ + MakeEmpty(); + free(fItems); +} + +// GetDefaultItem +template +inline +const List::item_t & +List::GetDefaultItem() const +{ + return sDefaultItem; +} + +// GetDefaultItem +template +inline +List::item_t & +List::GetDefaultItem() +{ + return sDefaultItem; +} + +// _MoveItems +template +inline +void +List::_MoveItems(item_t* items, int32 offset, int32 count) +{ + if (count > 0 && offset != 0) + memmove(items + offset, items, count * sizeof(item_t)); +} + +// AddItem +template +bool +List::AddItem(const item_t &item, int32 index) +{ + bool result = (index >= 0 && index <= fItemCount + && _Resize(fItemCount + 1)); + if (result) { + _MoveItems(fItems + index, 1, fItemCount - index - 1); + new(fItems + index) item_t(item); + } + return result; +} + +// AddItem +template +bool +List::AddItem(const item_t &item) +{ + bool result = true; + if ((int32)fCapacity > fItemCount) { + new(fItems + fItemCount) item_t(item); + fItemCount++; + } else { + if ((result = _Resize(fItemCount + 1))) + new(fItems + (fItemCount - 1)) item_t(item); + } + return result; +} + +// These don't use the copy constructor! +/* +// AddList +template +bool +List::AddList(list_t *list, int32 index) +{ + bool result = (list && index >= 0 && index <= fItemCount); + if (result && list->fItemCount > 0) { + int32 count = list->fItemCount; + result = _Resize(fItemCount + count); + if (result) { + _MoveItems(fItems + index, count, fItemCount - index - count); + memcpy(fItems + index, list->fItems, + list->fItemCount * sizeof(item_t)); + } + } + return result; +} + +// AddList +template +bool +List::AddList(list_t *list) +{ + bool result = (list); + if (result && list->fItemCount > 0) { + int32 index = fItemCount; + int32 count = list->fItemCount; + result = _Resize(fItemCount + count); + if (result) { + memcpy(fItems + index, list->fItems, + list->fItemCount * sizeof(item_t)); + } + } + return result; +} +*/ + +// RemoveItem +template +bool +List::RemoveItem(const item_t &item) +{ + int32 index = IndexOf(item); + bool result = (index >= 0); + if (result) + RemoveItem(index); + return result; +} + +// RemoveItem +template +bool +List::RemoveItem(int32 index) +{ + if (index >= 0 && index < fItemCount) { + fItems[index].~item_t(); + _MoveItems(fItems + index + 1, -1, fItemCount - index - 1); + _Resize(fItemCount - 1); + return true; + } + return false; +} + +// ReplaceItem +template +bool +List::ReplaceItem(int32 index, const item_t &item) +{ + if (index >= 0 && index < fItemCount) { + fItems[index] = item; + return true; + } + return false; +} + +// MoveItem +template +bool +List::MoveItem(int32 oldIndex, int32 newIndex) +{ + if (oldIndex >= 0 && oldIndex < fItemCount + && newIndex >= 0 && newIndex <= fItemCount) { + if (oldIndex < newIndex - 1) { + item_t item = fItems[oldIndex]; + _MoveItems(fItems + oldIndex + 1, -1, newIndex - oldIndex - 1); + fItems[newIndex] = item; + } else if (oldIndex > newIndex) { + item_t item = fItems[oldIndex]; + _MoveItems(fItems + newIndex, 1, oldIndex - newIndex); + fItems[newIndex] = item; + } + return true; + } + return false; +} + +// MakeEmpty +template +void +List::MakeEmpty() +{ + for (int32 i = 0; i < fItemCount; i++) + fItems[i].~item_t(); + _Resize(0); +} + +// CountItems +template +int32 +List::CountItems() const +{ + return fItemCount; +} + +// IsEmpty +template +bool +List::IsEmpty() const +{ + return (fItemCount == 0); +} + +// ItemAt +template +const List::item_t & +List::ItemAt(int32 index) const +{ + if (index >= 0 && index < fItemCount) + return fItems[index]; + return sDefaultItem; +} + +// ItemAt +template +List::item_t & +List::ItemAt(int32 index) +{ + if (index >= 0 && index < fItemCount) + return fItems[index]; + return sDefaultItem; +} + +// Items +template +const List::item_t * +List::Items() const +{ + return fItems; +} + +// IndexOf +template +int32 +List::IndexOf(const item_t &item) const +{ + for (int32 i = 0; i < fItemCount; i++) { + if (fItems[i] == item) + return i; + } + return -1; +} + +// HasItem +template +bool +List::HasItem(const item_t &item) const +{ + return (IndexOf(item) >= 0); +} + +// _Resize +template +bool +List::_Resize(size_t count) +{ + bool result = true; + // calculate the new capacity + int32 newSize = count; + if (newSize <= 0) + newSize = 1; + newSize = ((newSize - 1) / fChunkSize + 1) * fChunkSize; + // resize if necessary + if ((size_t)newSize != fCapacity) { + item_t* newItems + = (item_t*)realloc(fItems, newSize * sizeof(item_t)); + if (newItems) { + fItems = newItems; + fCapacity = newSize; + } else + result = false; + } + if (result) + fItemCount = count; + return result; +} + +#endif // LIST_H diff --git a/src/tests/kits/net/ppp/headers/Locker.h b/src/tests/kits/net/ppp/headers/Locker.h new file mode 100644 index 0000000000..de27138fc5 --- /dev/null +++ b/src/tests/kits/net/ppp/headers/Locker.h @@ -0,0 +1,63 @@ +// +// $Id: Locker.h,v 1.1 2003/07/06 16:46:29 wkornew Exp $ +// +// This is the BLocker interface for OpenBeOS. It has been created to +// be source and binary compatible with the BeOS version of BLocker. +// +// bonefish: Removed virtual from destructor. + + +#ifndef _OPENBEOS_LOCKER_H +#define _OPENBEOS_LOCKER_H + + +#include +#include + + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + +class BLocker { +public: + BLocker(); + BLocker(const char *name); + BLocker(bool benaphore_style); + BLocker(const char *name, bool benaphore_style); + + // The following constructor is not documented in the BeBook + // and is only listed here to ensure binary compatibility. + // DO NOT USE THIS CONSTRUCTOR! + BLocker(const char *name, bool benaphore_style, bool); + + ~BLocker(); + + bool Lock(void); + status_t LockWithTimeout(bigtime_t timeout); + void Unlock(void); + + thread_id LockingThread(void) const; + bool IsLocked(void) const; + int32 CountLocks(void) const; + int32 CountLockRequests(void) const; + sem_id Sem(void) const; + +private: + void InitLocker(const char *name, bool benaphore_style); + bool AcquireLock(bigtime_t timeout, status_t *error); + + int32 fBenaphoreCount; + sem_id fSemaphoreID; + thread_id fLockOwner; + int32 fRecursiveCount; + + // Reserved space for future changes to BLocker + int32 fReservedSpace[4]; +}; + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif + +#endif // _OPENBEOS_LOCKER_H diff --git a/src/tests/kits/net/ppp/headers/LockerHelper.h b/src/tests/kits/net/ppp/headers/LockerHelper.h new file mode 100644 index 0000000000..b53a83e0dd --- /dev/null +++ b/src/tests/kits/net/ppp/headers/LockerHelper.h @@ -0,0 +1,44 @@ +/* + * LockerHelper.h + * + * The LockerHelper acquires a lock on construction and releases it + * on destruction. + * This is a very useful class because you do not have to worry about + * releasing the lock at every possible point. It is done automatically. + * + */ + + +#ifndef _LOCKER_HELPER__H +#define _LOCKER_HELPER__H + +#include "Locker.h" + + +class LockerHelper { + public: + LockerHelper(BLocker &lock) : fLock(&lock) + { + if(fLock->Lock() != B_OK) + fLock = NULL; + } + + ~LockerHelper() + { + if(fLock) + fLock->Unlock(); + } + + void UnlockNow() + { + if(fLock) + fLock->Unlock(); + fLock = NULL; + } + + private: + BLocker *fLock; +}; + + +#endif diff --git a/src/tests/kits/net/ppp/src/KPPPFSM.cpp b/src/tests/kits/net/ppp/src/KPPPFSM.cpp new file mode 100644 index 0000000000..0124cb4689 --- /dev/null +++ b/src/tests/kits/net/ppp/src/KPPPFSM.cpp @@ -0,0 +1,594 @@ +#include "KPPPFSM.h" + + +PPPFSM::PPPFSM(PPPInterface &interface) + : fInterface(&interface), fPhase(PPP_CTOR_DTOR_PHASE), + fState(PPP_INITIAL_STATE), + fAuthenticationStatus(PPP_NOT_AUTHENTICATED), + fPeerAuthenticationStatus(PPP_NOT_AUTHENTICATED), + fAuthenticatorIndex(-1), fPeerAuthenticatorIndex(-1) +{ + +} + + +PPPFSM::~PPPFSM() +{ + +} + + +// remember: NewState() must always be called _after_ IllegalEvent() +// because IllegalEvent() also looks at the current state. +void +PPPFSM::NewState(PPP_STATE next) +{ + fState = next; +} + + +void +PPPFSM::LeaveConstructionPhase() +{ + LockerHelper locker(fLock); + fPhase = PPP_DOWN_PHASE; +} + + +PPPFSM::EnterDestructionPhase() +{ + LockerHelper locker(fLock); + fPhase = PPP_CTOR_DTOR_PHASE; +} + + +// authentication events +void +PPPFSM::AuthenticationRequested() +{ + // IMPLEMENT ME! +} + + +void +PPPFSM::AuthenticationAccepted(const char *name) +{ + // IMPLEMENT ME! +} + + +void +PPPFSM::AuthenticationDenied(const char *name) +{ + // IMPLEMENT ME! +} + + +const char* +PPPFSM::AuthenticationName() const +{ + // IMPLEMENT ME! +} + + +void +PPPFSM::PeerAuthenticationRequested() +{ + // IMPLEMENT ME! +} + + +void +PPPFSM::PeerAuthenticationAccepted(const char *name) +{ + // IMPLEMENT ME! +} + + +void +PPPFSM::PeerAuthenticationDenied(const char *name) +{ + // IMPLEMENT ME! +} + + +const char* +PPPFSM::PeerAuthenticationName() const +{ + // IMPLEMENT ME! +} + + +// public events +bool +PPPFSM::TLSNotify() +{ + LockerHelper locker(fLock); + + if(State() == PPP_STARTING_STATE) { + if(Phase() == PPP_DOWN_PHASE) + fPhase = PPP_ESTABLISHMENT_PHASE; + // this says that the device is going up + return true; + } + + return false; +} + + +bool +PPPFSM::TLFNotify() +{ + LockerHelper locker(fLock); + + if(Phase() == PPP_ESTABLISHMENT_PHASE) { + // we may not go down because an OpenEvent indicates that the + // user wants to connect + return false; + } + + // from now on no packets may be sent to the device + fPhase = PPP_DOWN_PHASE; + + return true; +} + + +void +PPPFSM::UpFailedEvent() +{ + LockerHelper locker(fLock); + + switch(State()) { + case PPP_STARTING_STATE: + // we must have called TLS() which 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 + // to go up + IllegalEvent(PPP_UP_FAILED_EVENT); + NewState(PPP_INITIAL_STATE); + break; + } + + // TODO: + // report that up failed + // Report(PPP_CONNECTION_REPORT, PPP_UP_FAILED, NULL, 0); + break; + + default: + IllegalEvent(PPP_UP_FAILED_EVENT); + } +} + + +void +PPPFSM::UpEvent() +{ + // This call is public, thus, it might not only be called by the device. + // We must recognize these attempts to fool us and handle them correctly. + + LockerHelper locker(fLock); + + if(!Device()->IsUp()) + return; + // it is not our device that went up... + + switch(State()) { + case PPP_INITIAL_STATE: + if(Mode() != PPP_SERVER_MODE + || Phase() != PPP_ESTABLISHMENT_PHASE) { + // we are a client or we do not listen for an incoming + // connection, so this is an illegal event + IllegalEvent(PPP_UP_EVENT); + NewState(PPP_CLOSED_STATE); + locker.UnlockNow(); + ThisLayerFinished(); + } + + // TODO: handle server-up! + break; + + case PPP_STARTING_STATE: + // we must have called TLS() which 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 + // to go up + IllegalEvent(PPP_UP_EVENT); + NewState(PPP_CLOSED_STATE); + locker.UnlockNow(); + ThisLayerFinished(); + break; + } + + InitializeRestartCounter(); + NewState(PPP_REQ_SENT_STATE); + locker.UnlockNow(); + SendConfigureRequest(); + break; + + default: + IllegalEvent(PPP_UP_EVENT); + } +} + + +void +PPPFSM::DownEvent() +{ + LockerHelper locker(fLock); + + // TODO: + // ResetProtocols(); + // ResetEncapsulators(); + + switch(State()) { + case PPP_CLOSED_STATE: + case PPP_CLOSING_STATE: + NewState(PPP_INITIAL_STATE); + fPhase = PPP_DOWN_PHASE; + break; + + case PPP_STOPPED_STATE: + // The RFC says we should reconnect, but our implementation + // will only do this if auto-redial is enabled (only clients). + NewStatus(PPP_STARTING_STATE); + fPhase = PPP_DOWN_PHASE; + + // 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); + fPhase = PPP_DOWN_PHASE; + + // 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); + fPhase = PPP_DOWN_PHASE; + + // 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); + fPhase = PPP_DOWN_PHASE; + + // TODO: + // report that we lost the connection + // Report(PPP_CONNECTION_REPORT, PPP_CONNECTION_LOST, NULL, 0); + break; + + default: + IllegalEvent(PPP_DOWN_EVENT); + } + + // maybe we need to redial + if(State() == PPP_STARTING_STATE) { + if(Interface()->DoesAutoRedial()) { + // TODO: + // redial using a new thread (maybe interface manager will help us) + } + } +} + + +// private events +void +PPPFSM::OpenEvent() +{ + LockerHelper locker(fLock); + + switch(State()) { + case PPP_INITIAL_STATE: + NewState(PPP_STARTING_STATE); + locker.UnlockNow(); + ThisLayerStarted(); + break; + + case PPP_CLOSED_STATE: + if(Phase() == PPP_DOWN_PHASE) { + // the device is already going down + return; + } + + InitializeRestartCounter(); + NewState(PPP_REQ_SENT_STATE); + fPhase = PPP_ESTABLISHMENT_PHASE; + locker.UnlockNow(); + SendConfigureRequest(); + break; + + case PPP_CLOSING_STATE: + NewState(PPP_STOPPING_STATE); + } +} + + +void +PPPFSM::CloseEvent() +{ + LockerHelper locker(fLock); + + switch(State()) { + case PPP_OPENED_STATE: + ThisLayerDown(); + + case PPP_REQ_SENT_STATE: + case PPP_ACK_RCVD_STATE: + case PPP_ACK_SENT_STATE: + InitializeRestartCounter(); + NewState(PPP_CLOSING_STATE); + fPhase = PPP_TERMINATION_PHASE; + locker.UnlockNow(); + SendTerminateRequest(); + break; + + case PPP_STARTING_STATE: + NewState(PPP_INITIAL_STATE); + + // if Device()->TLS() has not been called + // TLSNotify() will know that we were faster because we + // are in PPP_INITIAL_STATE now + if(Phase() == PPP_ESTABLISHMENT_PHASE) { + // the device is already up + fPhase = PPP_DOWN_PHASE; + // this says the following DownEvent() was not caused by + // a connection fault + locker.UnlockNow(); + ThisLayerFinished(); + } + break; + + case PPP_STOPPING_STATE: + NewState(PPP_CLOSING_STATE); + break; + + case PPP_STOPPED_STATE: + NewState(PPP_STOPPED_STATE); + break; + } +} + + +void +PPPFSM::TOGoodEvent() +{ + LockerHelper locker(fLock); + + switch(State()) { + case PPP_CLOSING_STATE: + case PPP_STOPPING_STATE: + locker.UnlockNow(); + SendTerminateRequest(); + break; + + case PPP_ACK_RCVD_STATE: + NewState(PPP_REQ_SENT_STATE); + + case PPP_REQ_SENT_STATE: + case PPP_ACK_SENT_STATE: + locker.UnlockNow(); + SendConfigureRequest(); + break; + + default: + IllegalEvent(PPP_TO_GOOD_EVENT); + } +} + + +void +PPPFSM::TOBadEvent() +{ + LockerHelper locker(fLock); + + switch(State()) { + case PPP_CLOSING_STATE: + NewState(PPP_CLOSED_STATE); + fPhase = PPP_TERMINATION_PHASE; + locker.UnlockNow(); + ThisLayerFinished(); + break; + + case PPP_STOPPING_STATE: + case PPP_REQ_SENT_STATE: + case PPP_ACK_RCVD_STATE: + case PPP_ACK_SENT_STATE: + NewState(PPP_STOPPED_STATE); + fPhase = PPP_TERMINATION_PHASE; + locker.UnlockNow(); + ThisLayerFinished(); + break; + + default: + IllegalEvent(PPP_TO_BAD_EVENT); + } +} + + +void +PPPFSM::RCRGoodEvent(PPPConfigurePacket *packet) +{ + LockerHelper locker(fLock); + + +} + + +void +PPPFSM::RCRBadEvent(PPPConfigurePacket *packet) +{ + LockerHelper locker(fLock); + +} + + +void +PPPFSM::RCAEvent(PPPConfigurePacket *packet) +{ + LockerHelper locker(fLock); + +} + + +void +PPPFSM::RCNEvent(PPPConfigurePacket *packet) +{ + LockerHelper locker(fLock); + +} + + +void +PPPFSM::RTREvent() +{ + LockerHelper locker(fLock); + +} + + +void +PPPFSM::RTAEvent() +{ + LockerHelper locker(fLock); + +} + + +void +PPPFSM::RUCEvent() +{ + LockerHelper locker(fLock); + +} + + +void +PPPFSM::RXJGoodEvent() +{ + LockerHelper locker(fLock); + +} + + +void +PPPFSM::RXJBadEvent() +{ + LockerHelper locker(fLock); + +} + + +void +PPPFSM::RXREvent() +{ + LockerHelper locker(fLock); + +} + + +// actions (all private) +void +PPPFSM::IllegalEvent(PPP_EVENT event) +{ + // update error statistics +} + + +void +PPPFSM::ThisLayerUp() +{ +} + + +void +PPPFSM::ThisLayerDown() +{ + // DownProtocols(); + // DownEncapsulators(); + // ResetProtocols(); + // ResetEncapsulators(); +} + + +void +PPPFSM::ThisLayerStarted() +{ +} + + +void +PPPFSM::ThisLayerFinished() +{ +} + + +void +PPPFSM::InitializeRestartCount() +{ +} + + +void +PPPFSM::ZeroRestartCount() +{ +} + + +void +PPPFSM::SendConfigureRequest() +{ +} + + +void +PPPFSM::SendConfigureAck(PPPConfigurePacket *packet) +{ +} + + +void +PPPFSM::SendConfigureNak(PPPConfigurePacket *packet) +{ + // is this needed? +} + + +void +PPPFSM::SendTerminateRequest() +{ +} + + +void +PPPFSM::SendTerminateAck() +{ +} + + +void +PPPFSM::SendCodeReject() +{ +} + + +void +PPPFSM::SendEchoReply() +{ +} diff --git a/src/tests/kits/net/ppp/src/KPPPInterface.cpp b/src/tests/kits/net/ppp/src/KPPPInterface.cpp new file mode 100644 index 0000000000..9e68a665d5 --- /dev/null +++ b/src/tests/kits/net/ppp/src/KPPPInterface.cpp @@ -0,0 +1,771 @@ +#include "KPPPInterface.h" + +// our other classes +#include "KPPPModule.h" +#include "KPPPManager.h" + +// general helper classes not only belonging to us +#include "AccessHelper.h" +#include "LockerHelper.h" + +// tools only for us :) +#include "KPPPUtils.h" +#include "settings_tools.h" + +#include + + +// TODO: +// - report module errors (when loading in ctor) +// (in InitCheck(), too) +// - add free-list for driver_settings that were loaded by Control() +// - implement timers +// - maybe some protocols must go down instead of being reset -> add flag for this + + +PPPInterface::PPPInterface(driver_settings *settings) + : fSettings(dup_driver_settings(settings)), + FSM(*this), LCP(*this), fIfnet(NULL), fLinkMTU(0), + fAccessing(0), fDevice(NULL), fFirstEncapsulator(NULL), + fGeneralLock(FSM().Locker()) +{ + if(!fSettings) + return; + + const char *value; + + value = get_settings_value(PPP_MODE_KEY, fsettings); + if(!strcasecmp(value, PPP_SERVER_MODE_VALUE)) + fMode = PPP_SERVER_MODE; + else + fMode = PPP_CLIENT_MODE; + // we are a client by default + + SetDialOnDemand( + get_boolean_value( + get_settings_value(PPP_DIAL_ON_DEMAND_KEY, fSettings), + false) + ); + // dial on demand is disabled by default + + + SetAutoRedial( + get_boolean_value( + get_settings_value(PPP_AUTO_REDIAL_KEY, fSettings), + false) + ); + // auto redial is disabled by default + + // load all protocols and the device + LoadModules(fSettings, 0, fSettings->parameter_count); + + FSM().LeaveConstructionPhase(); +} + + +PPPInterface::~PPPInterface() +{ + // TODO: + // remove our iface, so that nobody will access it: + // go down if up + // unregister from ppp_manager + + FSM().EnterDestructionPhase(); + + // destroy and remove: + // device + // protocols + // encapsulators + // option handlers + + // put all modules (in fModules) +} + + +status_t +PPPInterface::InitCheck() const +{ + if(!fDevice + || !fSettings) + return B_ERROR; + + return B_OK; +} + + +bool +PPPInterface::RegisterInterface() +{ + if(fIfnet) + return true; + // we are already registered + + if(!InitCheck()) + return false; + // we cannot register if something is wrong + + ppp_manager_info *manager; + if(get_module(PPP_MANAGER_MODULE_NAME, (module_info**) &manager) != B_OK) + return false; + + fIfnet = manager->add_interface(this); + + put_module((module_info**) &manager); + + + if(!fIfnet) + return false; + + return true; +} + + +bool +PPPInterface::UnregisterInterface() +{ + if(!fIfnet) + return true; + // we are already unregistered + + ppp_manager_info *manager; + if(get_module(PPP_MANAGER_MODULE_NAME, (module_info**) &manager) != B_OK) + return false; + + manager->remove_interface(this); + fIfnet = NULL; + + put_module((module_info**) &manager); + + return true; +} + + +void +PPPInterface::SetLinkMTU(uint32 linkMTU) +{ + if(linkMTU < fLinkMTU && linkMTU > 234) + fLinkMTU = linkMTU; +} + + +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 in right mode + // - setting AutoRedial and DialOnDemand + + + default: + return B_ERROR; + } + + return B_OK; +} + + +bool +PPPInterface::SetDevice(PPPDevice *device) +{ + if(!device) + return false; + + if(Phase() != PPP_CTOR_DTOR_PHASE) + return false; + // a running connection may not change + + if(fDevice && (IsUp() || fDevice->IsUp())) + Down(); + + fDevice = device; + + fLinkMTU = fDevice->MTU(); + + CalculateMRU(); +} + + +bool +PPPInterface::AddProtocol(PPPProtocol *protocol) +{ + if(!protocol) + return false; + + if(Phase() != PPP_CTOR_DTOR_PHASE) + return false; + // a running connection may not change + + fProtocols.AddItem(protocol); + + if(IsUp() || Phase() >= protocol->Phase()) + protocol->Up(); +} + + +bool +PPPInterface::RemoveProtocol(PPPProtocol *protocol) +{ + if(Phase() != PPP_CTOR_DTOR_PHASE) + return false; + // a running connection may not change + + if(!fProtocols.HasItem(protocol)) + return false; + + if(IsUp() || Phase() >= protocol->Phase()) + protocol->Down(); + + return fProtocols.RemoveItem(protocol); +} + + +PPPProtocol* +PPPInterface::ProtocolAt(int32 index) const +{ + PPPProtocol *protocol = fProtocols.ItemAt(index); + + if(protocol == fProtocols.GetDefaultItem()) + return NULL; + + return protocol; +} + + +PPPProtocol* +PPPInterface::ProtocolFor(uint16 protocol, int32 start = 0) const +{ + if(start < 0) + return NULL; + + for(int32 i = start; i < fProtocols.CountItems(); i++) + if(fProtocols.ItemAt(i)->Protocol() == protocol) + return fProtocols.ItemAt(i); + + return NULL; +} + + +bool +PPPInterface::AddEncapsulator(PPPEncapsulator *encapsulator) +{ + // Find instert position after the last encapsulator + // with the same level. + + if(!encapsulator) + return false; + + if(Phase() != PPP_CTOR_DTOR_PHASE) + return false; + // a running connection may not change + + PPPEncapsulator *current = fFirstEncapsulator, *previous = NULL; + + while(current) { + if(current->Level() < encapsulator->Level()) + break; + + previous = current; + current = current->Next(); + } + + if(!current) { + if(!previous) + fFirstEncapsulator = encapsulator; + else + previous->SetNext(encapsulator); + + encapsulator->SetNext(NULL); + } else { + encapsulator->SetNext(current); + + if(!previous) + fFirstEncapsulator = encapsulator; + else + previous->SetNext(encapsulator); + } + + CalculateMRU(); + + if(IsUp()) + encapsulator->Up(); + + return true; +} + + +bool +PPPInterface::RemoveEncapsulator(PPPEncapsulator *encapsulator) +{ + if(Phase() != PPP_CTOR_DTOR_PHASE) + return false; + // a running connection may not change + + PPPEncapsulator *current = fFirstEncapsulator, previous = NULL; + + while(current) { + if(current == encapsulator) { + if(IsUp()) + encapsulator->Down(); + + if(previous) + previous->SetNext(current->Next()); + else + fFirstEncapsulator = current->Next(); + + current->SetNext(NULL); + + CalculateMRU(); + + return true; + } + + previous = current; + current = current->Next(); + } + + return false; +} + + +PPPEncapsulator* +PPPInterface::EncapsulatorFor(uint16 protocol, + PPPEncapsulator start = NULL) const +{ + PPPEncapsulator *current = start ? start : fFirstEncapsulator; + + for(; current; current = current->Next()) + if(current->Protocol() == protocol) + return current; + + return current; +} + + +bool +PPPInterface::AddOptionHandler(PPPOptionHandler *handler) +{ + if(!handler) + return false + + if(Phase() != PPP_CTOR_DTOR_PHASE) + return false; + // a running connection may not change + + fOptionHandlers.AddItem(handler); +} + + +bool +PPPInterface::RemoveOptionHandler(PPPOptionHandler *handler) +{ + if(Phase() != PPP_CTOR_DTOR_PHASE) + return false; + // a running connection may not change + + return fOptionHandlers.RemoveItem(handler); +} + + +PPPOptionHandler* +PPPInterface::OptionHandlerAt(int32 index) const +{ + PPPOptionHandler *handler = fOptionHandlers.ItemAt(index); + + if(handler == fOptionHandlers.DefaultItem()) + return NULL; + + return handler; +} + + +void +PPPInterface::SetAutoRedial(bool autoredial = true) +{ + if(Mode() == PPP_CLIENT_MODE) + return false; + + LockerHelper locker(fGeneralLock); + + fAutoRedial = autoredial; +} + + +void +PPPInterface::SetDialOnDemand(bool dialondemand = true) +{ + if(Mode() != PPP_CLIENT_MODE) + return false; + + LockerHelper locker(fGeneralLock); + + fDialOnDemand = dialondemand; + + // check if we need to register/unregister + if(!Ifnet() && fDialOnDemand) + RegisterInterface(); + else if(Ifnet() && !fDialOnDemand && Phase() == PPP_DOWN_PHASE) + UnregisterInterface(); +} + + +bool +PPPInterface::Up() +{ + // ToDo: + // instead of waiting for state change we should wait until + // all retries are done + + if(!InitCheck() || Phase() != PPP_CTOR_DTOR_PHASE) + return false; + + if(IsUp()) + return true; + + // TODO: + // Add one-time connection report request and wait + // for results. If we lost the connection we should + // consider redialing. + + return false; +} + + +bool +PPPInterface::Down() +{ + // ToDo: + // instead of waiting for state change we should wait until + // all retries are done + + if(!InitCheck() || Phase() != PPP_CTOR_DTOR_PHASE) + return false; + + // TODO: + // Add one-time connection report request. + + return false; +} + + +bool +PPPInterface::IsUp() const +{ + LockerHelper locker(fGeneralLock); + if(Ifnet()) + return Ifnet()->if_flags & IFF_RUNNING; + + return false; +} + + +/* + +void +PPPInterface::EnableReports(PPP_REPORT type, thread_id thread, + bool needsVerification = false) +{ +} + + +void +PPPInterface::DisableReports(PPP_REPORT type, thread_id thread) +{ +} + + +bool +PPPInterface::Reports(PPP_REPORT type, thread_id thread) +{ +} + +*/ + + +bool +PPPInterface::LoadModules(const driver_settings *settings, + int32 start, int32 count) +{ + if(Phase() != PPP_CTOR_DTOR_PHASE) + return false; + // a running connection may not change + + int32 type; + // which type key was used for loading this module? + + for(int32 i = start; + i < settings->parameter_count && i < start + count; + i++) { + + type = -1; + + const char *name = settings->parameters[i].name; + + if(!strcasecmp(name, PPP_LOAD_MODULE_KEY)) + type = PPP_LOAD_MODULE_TYPE; + else if(!strcasecmp(name, PPP_DEVICE_KEY)) + type = PPP_DEVICE_TYPE; + else if(!strcasecmp(name, PPP_PROTOCOL_KEY)) + type = PPP_PROTOCOL_TYPE; + else if(!strcasecmp(name, PPP_AUTHENTICATOR_KEY)) + type = PPP_AUTHENTICATOR_TYPE; + else if(!strcasecmp(name, PPP_PEER_AUTHENTICATOR_KEY)) + type = PPP_PEER_AUTHENTICATOR_TYPE; + + if(type >= 0) + for(int32 value_id = 0; value_id < settings->parameters[i].value_count; + value_id++) + if(!LoadModule(settings->parameters[i].value[value_id], + settings->parameters[i].parameters, type)) + return false; + } + + return true; +} + + +bool +PPPInterface::LoadModule(const char *name, const driver_parameter *parameter, + int32 type) +{ + if(Phase() != PPP_CTOR_DTOR_PHASE) + return false; + // a running connection may not change + + if(!name || strlen(name) > B_FILE_NAME_LENGTH) + return false; + + char module_name[B_PATH_NAME_LENGTH]; + + sprintf(module_name, "%s/%s", PPP_MODULES_PATH, name); + + ppp_module_info *module; + if(get_module(module_name, (module_info**) &module) != B_OK) + return false; + + if(!module->add_to(this, parameter, type)) + return false; + + // add the module to the list of loaded modules + // for putting them on our destruction + return fModules.AddItem(module); +} + + +status_t +PPPInterface::Send(mbuf *packet, uint16 protocol) +{ + AccessHelper access(&fAccessing); + + if(!packet) + return B_ERROR; + + // we must pass the basic tests! + if(InitCheck() != B_OK) { + m_free(packet); + return B_ERROR; + } + + // test whether are going down + if(Phase() == PPP_TERMINATION_PHASE) { + m_free(packet); + return B_ERROR; + } + + // go up if DialOnDemand enabled and we are down + 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); + if(sending_protocol && sending_protocol->Flags() & PPP_ALWAYS_ALLOWED + && sending_protocol->IsEnabled() && fDevice->IsUp()) + return SendToDevice(packet, protocol); + + // never send normal protocols when we are down + if(!IsUp()) { + m_free(packet); + return B_ERROR; + } + + // send to next up encapsulator + if(!fFirstEncapsulator) + return SendToDevice(packet, protocol); + + if(!fFirstEncapsulator->IsEnabled()) + return fFirstEncapsulator->SendToNext(); + + return fFirstEncapsulator->Send(packet, protocol); +} + + +status_t +PPPInterface::Receive(mbuf *packet, uint16 protocol) +{ + AccessHelper access(&fAccessing); + + if(!packet) + return B_ERROR; + + int32 result = PPP_REJECTED; + // assume we have no handler + + // 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)) { + if(!encapsulator_handler->IsEnabled()) + continue; + // disabled handlers should not be used + result = encapsulator_handler->Receive(packet, protocol); + 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() + || !protocol_handler->IsEnabled()) + continue; + + result = protocol_handler->Receive(packet, protocol); + if(result == PPP_UNHANDLED) + continue; + + return result; + } + + // packet is unhandled + m_free(packet); + + if(result == PPP_UNHANDLED) + return PPP_DISCARDED; + else { + // TODO: + // send protocol-reject! + return PPP_REJECTED; + } +} + + +status_t +PPPInterface::SendToDevice(mbuf *packet, uint16 protocol) +{ + AccessHelper access(&fAccessing); + + if(!packet) + return B_ERROR; + + // we must pass the basic tests like: + // do we have a device? + // did we load all modules? + if(InitCheck() != B_OK) { + m_free(packet); + return B_ERROR; + } + + // test whether are going down + if(Phase() == PPP_TERMINATION_PHASE) { + m_free(packet); + return B_ERROR; + } + + // go up if DialOnDemand enabled and we are down + if(DoesDialOnDemand() && Phase() == PPP_DOWN_PHASE) + Up(); + + // 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() + ) + ) + ) { + m_free(packet); + return B_ERROR; + } + + // encode in ppp frame + M_PREPEND(packet, sizeof(uint16)); + + if(packet == NULL) + return B_ERROR; + + // set protocol (the only header field) + protocol = htons(protocol); + uint16 *header = mtod(packet, uint16*); + *header = protocol; + + // pass to device + return Device()->Send(packet); +} + + +status_t +PPPInterface::ReceiveFromDevice(mbuf *packet) +{ + AccessHelper access(&fAccessing); + + if(!packet) + return B_ERROR; + + if(!InitCheck()) { + m_free(packet); + return B_ERROR; + } + + // decode ppp frame + uint16 *protocol = mtod(packet, uint16*); + *protocol = ntohs(*protocol); + + m_adj(packet, sizeof(uint16)); + + if(packet->m_flags & M_PKTHDR) { + packet->m_pkthdr.rcvif = Ifnet(); + // make sure the protocols think we received + // the packet + + if(!packet->m_pkthdr.rcvif) { + m_free(packet); + return false; + } + } + + return Receive(packet, protocol); +} + + +void +PPPInterface::CalculateMRU() +{ + fMRU = fLinkMTU; + + // sum all headers + fHeaderLength = sizeof(uint16); + + PPPEncapsulator encapsulator = fFirstEncapsulator; + while(encapsulator) { + fHeaderLength += encapsulator->Overhead(); + encapsulator = encapsulator->Next(); + } + + fMRU -= fHeaderLength; + + if(Ifnet()) { + Ifnet()->if_mtu = fMRU; + Ifnet()->if_hdrlen = fHeaderLength; + } +} diff --git a/src/tests/kits/net/ppp/src/KPPPLCP.cpp b/src/tests/kits/net/ppp/src/KPPPLCP.cpp new file mode 100644 index 0000000000..494e79ddc8 --- /dev/null +++ b/src/tests/kits/net/ppp/src/KPPPLCP.cpp @@ -0,0 +1,2 @@ +#include "KPPPLCP.h" + diff --git a/src/tests/kits/net/ppp/src/Locker.cpp b/src/tests/kits/net/ppp/src/Locker.cpp new file mode 100644 index 0000000000..e33210ffcd --- /dev/null +++ b/src/tests/kits/net/ppp/src/Locker.cpp @@ -0,0 +1,297 @@ +// +// $Id: Locker.cpp,v 1.1 2003/07/06 16:46:29 wkornew Exp $ +// +// This file contains the OpenBeOS implementation of BLocker. +// + + +#include "Locker.h" +#include +#include + + +#ifdef USE_OPENBEOS_NAMESPACE +namespace OpenBeOS { +#endif + + +// +// Data Member Documentation: +// +// The "fBenaphoreCount" member is set to 1 if the BLocker style is +// semaphore. If the style is benaphore, it is initialized to 0 and +// is incremented atomically when it is acquired, decremented when it +// is released. By setting the benaphore count to 1 when the style is +// semaphore, the benaphore effectively becomes a semaphore. I was able +// to determine this is what Be's implementation does by testing the +// result of the CountLockRequests() member. +// +// The "fSemaphoreID" member holds the sem_id returned from create_sem() +// when the BLocker is constructed. It is used to acquire and release +// the lock regardless of the lock style (semaphore or benaphore). +// +// The "fLockOwner" member holds the thread_id of the thread which +// currently holds the lock. If no thread holds the lock, it is set to +// B_ERROR. +// +// The "fRecursiveCount" member holds a count of the number of times the +// thread holding the lock has acquired the lock without a matching unlock. +// It is basically the number of times the thread must call Unlock() before +// the lock can be acquired by a different thread. +// + + +// +// Constructors: +// +// All constructors just pass their arguments to InitLocker(). Note that +// the default for "name" is "some BLocker" and "benaphore_style" is true. +// + +BLocker::BLocker() +{ + InitLocker("some BLocker", true); +} + + +BLocker::BLocker(const char *name) +{ + InitLocker(name, true); +} + + +BLocker::BLocker(bool benaphore_style) +{ + InitLocker("some BLocker", benaphore_style); +} + + +BLocker::BLocker(const char *name, + bool benaphore_style) +{ + InitLocker(name, benaphore_style); +} + + +// +// This constructor is not documented. The final argument is ignored for +// now. In Be's headers, its called "for_IPC". DO NOT USE THIS +// CONSTRUCTOR! +// +BLocker::BLocker(const char *name, + bool benaphore_style, + bool) +{ + InitLocker(name, benaphore_style); +} + + +// +// The destructor just deletes the semaphore. By deleting the semaphore, +// any threads waiting to acquire the BLocker will be unblocked. +// +BLocker::~BLocker() +{ + delete_sem(fSemaphoreID); +} + + +bool +BLocker::Lock(void) +{ + status_t result; + + return (AcquireLock(B_INFINITE_TIMEOUT, &result)); +} + + +status_t +BLocker::LockWithTimeout(bigtime_t timeout) +{ + status_t result; + + AcquireLock(timeout, &result); + return result; +} + + + +void +BLocker::Unlock(void) +{ + // If the thread currently holds the lockdecrement + if (IsLocked()) { + + // Decrement the number of outstanding locks this thread holds + // on this BLocker. + fRecursiveCount--; + + // If the recursive count is now at 0, that means the BLocker has + // been released by the thread. + if (fRecursiveCount == 0) { + + // The BLocker is no longer owned by any thread. + fLockOwner = B_ERROR; + + // Decrement the benaphore count and store the undecremented + // value in oldBenaphoreCount. + int32 oldBenaphoreCount = atomic_add(&fBenaphoreCount, -1); + + // If the oldBenaphoreCount is greater than 1, then there is + // at lease one thread waiting for the lock in the case of a + // benaphore. + if (oldBenaphoreCount > 1) { + + // Since there are threads waiting for the lock, it must + // be released. Note, the old benaphore count will always be + // greater than 1 for a semaphore so the release is always done. + release_sem(fSemaphoreID); + } + } + } +} + + +thread_id +BLocker::LockingThread(void) const +{ + return fLockOwner; +} + + +bool +BLocker::IsLocked(void) const +{ + // This member returns true if the calling thread holds the lock. + // The easiest way to determine this is to compare the result of + // find_thread() to the fLockOwner. + return (find_thread(NULL) == fLockOwner); +} + + +int32 +BLocker::CountLocks(void) const +{ + return fRecursiveCount; +} + + +int32 +BLocker::CountLockRequests(void) const +{ + return fBenaphoreCount; +} + + +sem_id +BLocker::Sem(void) const +{ + return fSemaphoreID; +} + + +void +BLocker::InitLocker(const char *name, + bool benaphore) +{ + if (benaphore) { + // Because this is a benaphore, initialize the benaphore count and + // create the semaphore. Because this is a benaphore, the semaphore + // count starts at 0 (ie acquired). + fBenaphoreCount = 0; + fSemaphoreID = create_sem(0, name); + } else { + // Because this is a semaphore, initialize the benaphore count to -1 + // and create the semaphore. Because this is semaphore style, the + // semaphore count starts at 1 so that one thread can acquire it and + // the next thread to acquire it will block. + fBenaphoreCount = 1; + fSemaphoreID = create_sem(1, name); + } + + // The lock is currently not acquired so there is no owner. + fLockOwner = B_ERROR; + + // The lock is currently not acquired so the recursive count is zero. + fRecursiveCount = 0; +} + + +bool +BLocker::AcquireLock(bigtime_t timeout, + status_t *error) +{ + // By default, return no error. + *error = B_NO_ERROR; + + // Only try to acquire the lock if the thread doesn't already own it. + if (!IsLocked()) { + + // Increment the benaphore count and test to see if it was already greater + // than 0. If it is greater than 0, then some thread already has the + // benaphore or the style is a semaphore. Either way, we need to acquire + // the semaphore in this case. + int32 oldBenaphoreCount = atomic_add(&fBenaphoreCount, 1); + if (oldBenaphoreCount > 0) { + + *error = acquire_sem_etc(fSemaphoreID, 1, B_RELATIVE_TIMEOUT, + timeout); + // Note, if the lock here does time out, the benaphore count + // is not decremented. By doing this, the benaphore count will + // never go back to zero. This means that the locking essentially + // changes to semaphore style if this was a benaphore. + // + // Doing the decrement of the benaphore count when the acquisition + // fails is a risky thing to do. If you decrement the counter at + // the same time the thread which holds the benaphore does an + // Unlock(), there is serious risk of a race condition. + // + // If the Unlock() sees a positive count and releases the semaphore + // and then the timed out thread decrements the count to 0, there + // is no one to take the semaphore. The next two threads will be + // able to acquire the benaphore at the same time! The first will + // increment the counter and acquire the lock. The second will + // acquire the semaphore and therefore the lock. Not good. + // + // This has been discussed on the becodetalk mailing list and + // Trey from Be had this to say: + // + // I looked at the LockWithTimeout() code, and it does not have + // _this_ (ie the race condition) problem. It circumvents it by + // NOT doing the atomic_add(&count, -1) if the semaphore + // acquisition fails. This means that if a + // BLocker::LockWithTimeout() times out, all other Lock*() attempts + // turn into guaranteed semaphore grabs, _with_ the overhead of a + // (now) useless atomic_add(). + // + // Given Trey's comments, it looks like Be took the same approach + // I did. The output of CountLockRequests() of Be's implementation + // confirms Trey's comments also. + // + // Finally some thoughts for the future with this code: + // - If 2^31 timeouts occur on a 32-bit machine (ie today), + // the benaphore count will wrap to a negative number. This + // would have unknown consequences on the ability of the BLocker + // to continue to function. + // + } + } + + // If the lock has successfully been acquired. + if (*error == B_NO_ERROR) { + + // Set the lock owner to this thread and increment the recursive count + // by one. The recursive count is incremented because one more Unlock() + // is now required to release the lock (ie, 0 => 1, 1 => 2 etc). + fLockOwner = find_thread(NULL); + fRecursiveCount++; + } + + // Return true if the lock has been acquired. + return (*error == B_NO_ERROR); +} + + +#ifdef USE_OPENBEOS_NAMESPACE +} +#endif diff --git a/src/tests/kits/net/ppp/src/settings_tools.cpp b/src/tests/kits/net/ppp/src/settings_tools.cpp new file mode 100644 index 0000000000..7c68cd898a --- /dev/null +++ b/src/tests/kits/net/ppp/src/settings_tools.cpp @@ -0,0 +1,123 @@ +#include "settings_tools.h" + +#include +#include + + +static void copy_parameter(const driver_parameter *from, driver_parameter *to); +static void free_driver_parameter(driver_parameter *p); + + +driver_settings *dup_driver_settings(const driver_settings *dup) +{ + if(!settings) + return NULL; // we got a NULL pointer, so return nothing + + driver_settings *ret = (driver_settings*) malloc(sizeof(driver_settings)); + + ret->parameter_count = dup->parameter_count; + ret->parameters = (driver_parameter*) malloc(ret->parameter_count * sizeof(driver_parameter)); + + for(int32 i=0; i < ret->parameter_count; i++) + copy_parameter(&dup->parameters[i], &ret->parameters[i]); + + return ret; +} + + +static void copy_parameter(const driver_parameter *from, driver_parameter *to) +{ + to->name = strdup(from->name); + to->value_count = from->value_count; + + to->values = (char**) malloc(values * sizeof(char*)); + + for(int32 i=0; i < to->value_count; i++) + to->values[i] = strdup(from->values[i]); + + to->parameter_count = from->parameter_count; + + to->parameters = (driver_parameter*) malloc(to->parameter_count * sizeof(driver_parameter)); + + for(int32 i=0; i < to->parameter_count; i++) + copy_parameter(&from->parameters[i], &to->parameters[i]); +} + + +void free_driver_settings(driver_settings *settings) +{ + for(int32 i=0; i < settings->parameter_count; i++) + free_driver_parameter(&settings->parameters[i]); + + free(settings->parameters); + free(settings); +} + + +void free_driver_parameter(driver_parameter *p) +{ + free(p->name); + + for(int32 i=0; i < p->value_count; i++) + free(p->values[i]); + + free(p->values); + + for(int32 i=0; i < p->parameter_count; i++) + free_driver_parameter(&p->parameters[i]); + + free(p->parameters); +} + + +void add_settings(const driver_settings *from, driver_settings *to) +{ + if(!from || !to) + return; + + to->parameters = realloc(to->parameters, + (to->parameter_count + from->parameter_count) * sizeof(driver_parameter)); + + for(int32 i=0; i < from->parameter_count; i++) + copy_parameters(&from->parameters[i], &to->parameters[to->parameter_count++]); +} + + +bool get_boolean_value(const char *string, bool unknownValue) +{ + if(!string) + return unknownValue; + + if (!strcmp(boolean, "1") + || !strcasecmp(boolean, "true") + || !strcasecmp(boolean, "yes") + || !strcasecmp(boolean, "on") + || !strcasecmp(boolean, "enable") + || !strcasecmp(boolean, "enabled")) + return true; + + if (!strcmp(boolean, "0") + || !strcasecmp(boolean, "false") + || !strcasecmp(boolean, "no") + || !strcasecmp(boolean, "off") + || !strcasecmp(boolean, "disable") + || !strcasecmp(boolean, "disabled")) + return false; + + // no correct value has been found => return default value + return unknownValue; +} + + +const char *get_settings_value(const char *name, const driver_settings *settings) +{ + if(!name || !settings) + return NULL; + + for(int32 i=0; i < settings->parameter_count; i++) + if(!strcasecmp(settings->parameters[i].name, name) + && settings->parameters[i].value_count > 0) + return settings->parameters[i].values[0]; + + return NULL; +} diff --git a/src/tests/kits/net/ppp/src/settings_tools.h b/src/tests/kits/net/ppp/src/settings_tools.h new file mode 100644 index 0000000000..0445fb4ade --- /dev/null +++ b/src/tests/kits/net/ppp/src/settings_tools.h @@ -0,0 +1,24 @@ +#ifndef _SETTINGS_TOOLS__H +#define _SETTINGS_TOOLS__H + +struct driver_settings; +struct driver_parameter; + + +driver_settings *dup_driver_settings(const driver_settings *settings); +void free_driver_settings(driver_settings *settings); + +void add_settings(const driver_settings *from, driver_settings *to); +void add_settings(const driver_settings *from, driver_parameter *to) + { add_settings(from, (driver_settings*) &to->parameter_count); } +void add_parameter(const driver_parameter *from, driver_settings *to) + { add_settings((driver_settings*) &from->parameter_count, to); } +void add_parameter(const driver_parameter *from, driver_parameter *to) + { add_settings((driver_settings*) &from->parameter_count, + (driver_settings*) &to->parameter_count); } + +bool get_boolean_value(const char *string, bool unknownValue); +const char *get_settings_value(const char *name, const driver_settings *settings); + + +#endif