Initial checkin of ppp stack.

Still far from being complete.
Comments are welcome.

In brief: Stack will be modular and written in C++.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3875 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Waldemar Kornewald 2003-07-06 16:46:29 +00:00
parent cb6670b490
commit 0491e1650c
21 changed files with 3142 additions and 0 deletions

View File

@ -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 <OS.h>
#include <SupportDefs.h>
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

View File

@ -0,0 +1,36 @@
#ifndef _K_PPP_CONFIGURE_PACKET__H
#define _K_PPP_CONFIGURE_PACKET__H
#include <mbuf.h>
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

View File

@ -0,0 +1,185 @@
#ifndef _K_PPP_DEFS__H
#define _K_PPP_DEFS__H
#include <Errors.h>
// 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,142 @@
#ifndef _K_PPP_INTERFACE__H
#define _K_PPP_INTERFACE__H
#include <driver_settings.h>
#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<PPPProtocol*> fProtocols;
List<PPPOptionHandler*> fOptionHandlers;
List<ppp_module_info*> fModules;
BLocker &fGeneralLock;
};
#endif

View File

@ -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

View File

@ -0,0 +1,30 @@
#ifndef _K_PPP_MANAGER__H
#define _K_PPP_MANAGER__H
#include <net_module.h>
#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

View File

@ -0,0 +1,16 @@
#ifndef _K_PPP_MODULE__H
#define _K_PPP_MODULE__H
#include <module.h>
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

View File

@ -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

View File

@ -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

View File

@ -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 <new.h>
#include <stdlib.h>
#include <string.h>
#include <SupportDefs.h>
template<typename ITEM>
class DefaultDefaultItemCreator {
public:
static inline ITEM GetItem() { return ITEM(0); }
};
/*!
\class List
\brief A generic list implementation.
*/
template<typename ITEM,
typename DEFAULT_ITEM_SUPPLIER = DefaultDefaultItemCreator<ITEM> >
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<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
List<ITEM, DEFAULT_ITEM_SUPPLIER>::item_t
List<ITEM, DEFAULT_ITEM_SUPPLIER>::sDefaultItem(
DEFAULT_ITEM_SUPPLIER::GetItem());
// constructor
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
List<ITEM, DEFAULT_ITEM_SUPPLIER>::List(size_t chunkSize)
: fCapacity(0),
fChunkSize(chunkSize),
fItemCount(0),
fItems(NULL)
{
if (fChunkSize == 0 || fChunkSize > kMaximalChunkSize)
fChunkSize = kDefaultChunkSize;
_Resize(0);
}
// destructor
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
List<ITEM, DEFAULT_ITEM_SUPPLIER>::~List()
{
MakeEmpty();
free(fItems);
}
// GetDefaultItem
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
inline
const List<ITEM, DEFAULT_ITEM_SUPPLIER>::item_t &
List<ITEM, DEFAULT_ITEM_SUPPLIER>::GetDefaultItem() const
{
return sDefaultItem;
}
// GetDefaultItem
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
inline
List<ITEM, DEFAULT_ITEM_SUPPLIER>::item_t &
List<ITEM, DEFAULT_ITEM_SUPPLIER>::GetDefaultItem()
{
return sDefaultItem;
}
// _MoveItems
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
inline
void
List<ITEM, DEFAULT_ITEM_SUPPLIER>::_MoveItems(item_t* items, int32 offset, int32 count)
{
if (count > 0 && offset != 0)
memmove(items + offset, items, count * sizeof(item_t));
}
// AddItem
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::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<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::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<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::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<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::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<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::RemoveItem(const item_t &item)
{
int32 index = IndexOf(item);
bool result = (index >= 0);
if (result)
RemoveItem(index);
return result;
}
// RemoveItem
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::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<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::ReplaceItem(int32 index, const item_t &item)
{
if (index >= 0 && index < fItemCount) {
fItems[index] = item;
return true;
}
return false;
}
// MoveItem
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::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<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
void
List<ITEM, DEFAULT_ITEM_SUPPLIER>::MakeEmpty()
{
for (int32 i = 0; i < fItemCount; i++)
fItems[i].~item_t();
_Resize(0);
}
// CountItems
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
int32
List<ITEM, DEFAULT_ITEM_SUPPLIER>::CountItems() const
{
return fItemCount;
}
// IsEmpty
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::IsEmpty() const
{
return (fItemCount == 0);
}
// ItemAt
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
const List<ITEM, DEFAULT_ITEM_SUPPLIER>::item_t &
List<ITEM, DEFAULT_ITEM_SUPPLIER>::ItemAt(int32 index) const
{
if (index >= 0 && index < fItemCount)
return fItems[index];
return sDefaultItem;
}
// ItemAt
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
List<ITEM, DEFAULT_ITEM_SUPPLIER>::item_t &
List<ITEM, DEFAULT_ITEM_SUPPLIER>::ItemAt(int32 index)
{
if (index >= 0 && index < fItemCount)
return fItems[index];
return sDefaultItem;
}
// Items
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
const List<ITEM, DEFAULT_ITEM_SUPPLIER>::item_t *
List<ITEM, DEFAULT_ITEM_SUPPLIER>::Items() const
{
return fItems;
}
// IndexOf
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
int32
List<ITEM, DEFAULT_ITEM_SUPPLIER>::IndexOf(const item_t &item) const
{
for (int32 i = 0; i < fItemCount; i++) {
if (fItems[i] == item)
return i;
}
return -1;
}
// HasItem
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::HasItem(const item_t &item) const
{
return (IndexOf(item) >= 0);
}
// _Resize
template<typename ITEM, typename DEFAULT_ITEM_SUPPLIER>
bool
List<ITEM, DEFAULT_ITEM_SUPPLIER>::_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

View File

@ -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 <OS.h>
#include <SupportDefs.h>
#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

View File

@ -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

View File

@ -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()
{
}

View File

@ -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 <cstring>
// 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;
}
}

View File

@ -0,0 +1,2 @@
#include "KPPPLCP.h"

View File

@ -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 <OS.h>
#include <SupportDefs.h>
#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

View File

@ -0,0 +1,123 @@
#include "settings_tools.h"
#include <cstring>
#include <driver_settings.h>
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;
}

View File

@ -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