Implemented support for default interface and ConnectOnDemand within core. IPCP will probably need more tweaking, did not have a look at that.

Interface statistics are now maintained.
If I did not forget anything the core stack is now feature-complete.
Only ppp_up must be finished, bugs and hacks found, and modem support added; that's it for R1, I hope.
Everyting untested!


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10541 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Waldemar Kornewald
2004-12-27 15:02:14 +00:00
parent eb89d62ca5
commit e91b737412
10 changed files with 118 additions and 15 deletions
@@ -110,6 +110,7 @@ pulse_timer(void *data)
PPPManager::PPPManager() PPPManager::PPPManager()
: fLock("PPPManager"), : fLock("PPPManager"),
fReportLock("PPPManagerReportLock"), fReportLock("PPPManagerReportLock"),
fDefaultInterface(NULL),
fReportManager(fReportLock), fReportManager(fReportLock),
fNextID(1) fNextID(1)
{ {
@@ -740,6 +741,34 @@ PPPManager::EntryFor(const driver_settings *settings) const
} }
void
PPPManager::SettingsChanged()
{
// get default interface name and update interfaces if it changed
void *handle = load_driver_settings("ptpnet.settings");
char *name = get_driver_parameter(handle, "default", NULL, NULL);
if(name)
name = strdup(name);
unload_driver_settings(handle);
if((!fDefaultInterface && !name) || !strcmp(name, fDefaultInterface))
return;
ppp_interface_entry *entry = EntryFor(fDefaultInterface);
if(entry && entry->interface
&& entry->interface->StateMachine().Phase() == PPP_DOWN_PHASE)
DeleteInterface(entry->interface->ID());
free(fInterfaceName);
fInterfaceName = name;
ppp_interface_id id = CreateInterfaceWithName(name);
entry = EntryFor(id);
if(entry && entry->interface)
entry->interface->SetConnectOnDemand(true);
}
static static
int int
greater(const void *a, const void *b) greater(const void *a, const void *b)
@@ -827,8 +856,7 @@ PPPManager::_CreateInterface(const char *name, const driver_settings *settings,
ERROR("KPPPInterface::Up(): Error: could not load ppp_up!\n"); ERROR("KPPPInterface::Up(): Error: could not load ppp_up!\n");
resume_thread(app); resume_thread(app);
// XXX: What? BeOS' kernel is so &$$§$%! I cannot send anything to the // XXX: Sending to a thread does not work immediately. So, we wait...
// team's main thread before the kernel sent something to it. So, we wait...
snooze(150000); snooze(150000);
if(send_data(app, 0, &id, sizeof(id)) < B_OK) if(send_data(app, 0, &id, sizeof(id)) < B_OK)
@@ -895,6 +923,9 @@ PPPManager::DeleterThreadEvent()
{ {
LockerHelper locker(fLock); LockerHelper locker(fLock);
SettingsChanged();
// TODO: Use Haiku's kernel node monitoring capabilities
// delete and remove marked interfaces // delete and remove marked interfaces
ppp_interface_entry *entry; ppp_interface_entry *entry;
for(int32 index = 0; index < fEntries.CountItems(); index++) { for(int32 index = 0; index < fEntries.CountItems(); index++) {
@@ -906,6 +937,11 @@ PPPManager::DeleterThreadEvent()
} }
if(entry->deleting && entry->accessing <= 0) { if(entry->deleting && entry->accessing <= 0) {
// XXX: check twice if it is safe to delete the interface
// such that it is reused by _CreateInterface()
delete entry->interface;
entry->interface = NULL;
// only remove entries that do not have ppp_up associated with them // only remove entries that do not have ppp_up associated with them
if(entry->requestThread >= 0) { if(entry->requestThread >= 0) {
thread_info info; thread_info info;
@@ -913,8 +949,17 @@ PPPManager::DeleterThreadEvent()
continue; continue;
} }
// recreate default interface
if(entry->name && fDefaultInterface &&
!strcmp(entry->name, fDefaultInterface)) {
SettingsChanged();
CreateInterfaceWithName(fDefaultInterface);
if(entry->interface)
entry->interface->SetConnectOnDemand(true);
continue;
}
free(entry->name); free(entry->name);
delete entry->interface;
delete entry; delete entry;
fEntries.RemoveItem(index); fEntries.RemoveItem(index);
--index; --index;
@@ -60,6 +60,8 @@ class PPPManager {
ppp_interface_entry *EntryFor(const char *name, int32 *saveIndex = NULL) const; ppp_interface_entry *EntryFor(const char *name, int32 *saveIndex = NULL) const;
ppp_interface_entry *EntryFor(const driver_settings *settings) const; ppp_interface_entry *EntryFor(const driver_settings *settings) const;
void SettingsChanged();
ppp_interface_id NextID() ppp_interface_id NextID()
{ return (ppp_interface_id) atomic_add((int32*) &fNextID, 1); } { return (ppp_interface_id) atomic_add((int32*) &fNextID, 1); }
@@ -74,6 +76,7 @@ class PPPManager {
private: private:
BLocker fLock, fReportLock; BLocker fLock, fReportLock;
char *fDefaultInterface;
KPPPReportManager fReportManager; KPPPReportManager fReportManager;
TemplateList<ppp_interface_entry*> fEntries; TemplateList<ppp_interface_entry*> fEntries;
ppp_interface_id fNextID; ppp_interface_id fNextID;
@@ -95,6 +95,7 @@ KPPPInterface::KPPPInterface(const char *name, ppp_interface_entry *entry,
fConnectRetry(0), fConnectRetry(0),
fConnectRetriesLimit(0), fConnectRetriesLimit(0),
fManager(NULL), fManager(NULL),
fConnectedSince(0),
fIdleSince(0), fIdleSince(0),
fMRU(1500), fMRU(1500),
fInterfaceMTU(1498), fInterfaceMTU(1498),
@@ -121,8 +122,8 @@ KPPPInterface::KPPPInterface(const char *name, ppp_interface_entry *entry,
if(name) { if(name) {
// load settings from description file // load settings from description file
char path[B_PATH_NAME_LENGTH]; char path[B_PATH_NAME_LENGTH];
sprintf(path, "pppidf/%s", name); sprintf(path, "ptpnet/%s", name);
// XXX: TODO: change base path to "/etc/ppp" when settings API supports it // XXX: TODO: change base path to "/etc/ptpnet"
void *handle = load_driver_settings(path); void *handle = load_driver_settings(path);
if(!handle) { if(!handle) {
@@ -489,6 +490,13 @@ KPPPInterface::Control(uint32 op, void *data, size_t length)
UpdateProfile(); UpdateProfile();
} break; } break;
case PPPC_GET_STATISTICS: {
if(length < sizeof(ppp_statistics) || !data)
return B_ERROR;
memcpy(data, &fStatistics, sizeof(ppp_statistics));
} break;
case PPPC_CONTROL_DEVICE: { case PPPC_CONTROL_DEVICE: {
if(length < sizeof(ppp_control_info) || !data) if(length < sizeof(ppp_control_info) || !data)
return B_ERROR; return B_ERROR;
@@ -1373,12 +1381,22 @@ KPPPInterface::Send(struct mbuf *packet, uint16 protocolNumber)
// pass to device/children // pass to device/children
if(!IsMultilink() || Parent()) { if(!IsMultilink() || Parent()) {
// check if packet is too big for device // check if packet is too big for device
if((packet->m_flags & M_PKTHDR && (uint32) packet->m_pkthdr.len > MRU()) uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len :
|| packet->m_len > MRU()) { packet->m_len;
if(length > MRU()) {
m_freem(packet); m_freem(packet);
return B_ERROR; return B_ERROR;
} }
// TODO: always use atomic_add64 when Haiku is finished
#ifdef __HAIKU__
atomic_add64(&fStatistics.bytesSent, length);
atomic_add64(&fStatistics.packetsSent, 1);
#else
atomic_add((int32*) &fStatistics.bytesSent, length);
atomic_add((int32*) &fStatistics.packetsSent, 1);
#endif
return SendToNext(packet, 0); return SendToNext(packet, 0);
// this is normally the device, but there can be something inbetween // this is normally the device, but there can be something inbetween
} else { } else {
@@ -1488,6 +1506,9 @@ KPPPInterface::ReceiveFromDevice(struct mbuf *packet)
return B_ERROR; return B_ERROR;
} }
uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len :
packet->m_len;
// decode ppp frame and recognize PFC // decode ppp frame and recognize PFC
uint16 protocolNumber = *mtod(packet, uint8*); uint16 protocolNumber = *mtod(packet, uint8*);
if(protocolNumber & 1) { if(protocolNumber & 1) {
@@ -1497,6 +1518,14 @@ KPPPInterface::ReceiveFromDevice(struct mbuf *packet)
m_adj(packet, 2); m_adj(packet, 2);
} }
// TODO: always use atomic_add64 when Haiku is finished
#ifdef __HAIKU__
atomic_add64(&fStatistics.bytesReceived, length);
atomic_add64(&fStatistics.packetsReceived, 1);
#else
atomic_add((int32*) &fStatistics.bytesReceived, length);
atomic_add((int32*) &fStatistics.packetsReceived, 1);
#endif
return Receive(packet, protocolNumber); return Receive(packet, protocolNumber);
} }
@@ -82,7 +82,7 @@ KPPPProfile::LoadSettings(const driver_settings *profile,
name = Interface().Name(); name = Interface().Name();
if(name) { if(name) {
sprintf(path, "pppidf/profile/%s", name); sprintf(path, "ptpnet/profile/%s", name);
void *handle = load_driver_settings(path); void *handle = load_driver_settings(path);
if(handle) { if(handle) {
fSettings = dup_driver_settings(get_driver_settings(handle)); fSettings = dup_driver_settings(get_driver_settings(handle));
@@ -129,6 +129,7 @@ KPPPStateMachine::NewPhase(ppp_phase next)
Interface().Report(PPP_CONNECTION_REPORT, PPP_REPORT_UP_SUCCESSFUL, Interface().Report(PPP_CONNECTION_REPORT, PPP_REPORT_UP_SUCCESSFUL,
&fInterface.fID, sizeof(ppp_interface_id)); &fInterface.fID, sizeof(ppp_interface_id));
Interface().fConnectedSince = system_time();
} }
} }
@@ -12,6 +12,10 @@
#include <KPPPDefs.h> #include <KPPPDefs.h>
#endif #endif
#ifndef _PPP_CONTROL__H
#include <PPPControl.h>
#endif
#ifndef _K_PPP_LCP__H #ifndef _K_PPP_LCP__H
#include <KPPPLCP.h> #include <KPPPLCP.h>
#endif #endif
@@ -262,6 +266,8 @@ class KPPPInterface : public KPPPLayer {
ppp_interface_module_info *fManager; ppp_interface_module_info *fManager;
ppp_statistics fStatistics;
bigtime_t fConnectedSince;
uint32 fIdleSince, fDisconnectAfterIdleSince; uint32 fIdleSince, fDisconnectAfterIdleSince;
bool fUpdateIdleSince; bool fUpdateIdleSince;
uint32 fMRU, fInterfaceMTU, fHeaderLength; uint32 fMRU, fInterfaceMTU, fHeaderLength;
@@ -51,6 +51,7 @@ enum ppp_control_ops {
PPPC_SET_AUTO_RECONNECT, PPPC_SET_AUTO_RECONNECT,
PPPC_HAS_INTERFACE_SETTINGS, PPPC_HAS_INTERFACE_SETTINGS,
PPPC_SET_PROFILE, PPPC_SET_PROFILE,
PPPC_GET_STATISTICS,
// handler access // handler access
PPPC_CONTROL_DEVICE = PPP_INTERFACE_OPS_START + 0xFF, PPPC_CONTROL_DEVICE = PPP_INTERFACE_OPS_START + 0xFF,
@@ -153,6 +154,8 @@ typedef struct ppp_interface_info {
uint32 connectRetry, connectRetriesLimit; uint32 connectRetry, connectRetriesLimit;
uint32 connectRetryDelay, reconnectDelay; uint32 connectRetryDelay, reconnectDelay;
bigtime_t connectedSince;
// undefined if disconnected
uint32 idleSince, disconnectAfterIdleSince; uint32 idleSince, disconnectAfterIdleSince;
bool doesConnectOnDemand, doesAutoReconnect, hasDevice, isMultilink, hasParent; bool doesConnectOnDemand, doesAutoReconnect, hasDevice, isMultilink, hasParent;
@@ -167,6 +170,18 @@ typedef struct ppp_interface_info_t {
} ppp_interface_info_t; } ppp_interface_info_t;
//! Structure used by \c PPPC_GET_STATISTICS.
typedef struct ppp_statistics {
uint64 bytesReceived, packetsReceived;
uint64 bytesSent, packetsSent;
// TODO: currently unused
uint64 errorBytesReceived, errorPacketsReceived;
// TODO: add compression statistics?
uint8 _reserved_[80];
} ppp_statistics;
//! Structure used by \c PPPC_GET_DEVICE_INFO. //! Structure used by \c PPPC_GET_DEVICE_INFO.
typedef struct ppp_device_info { typedef struct ppp_device_info {
char name[PPP_HANDLER_NAME_LENGTH_LIMIT + 1]; char name[PPP_HANDLER_NAME_LENGTH_LIMIT + 1];
@@ -15,13 +15,13 @@ typedef uint32 ppp_interface_id;
// settings keys // settings keys
#define PPP_ASK_BEFORE_CONNECTING_KEY "AskBeforeConnecting" #define PPP_ASK_BEFORE_CONNECTING_KEY "AskBeforeConnecting"
// userland ppp_up and preflet handle this key // userland ppp_up and preflet handle this key
#define PPP_DISONNECT_AFTER_IDLE_SINCE_KEY "DisonnectAfterIdleSince" #define PPP_DISONNECT_AFTER_IDLE_SINCE_KEY "DisonnectAfterIdleSince"
#define PPP_MODE_KEY "Mode" #define PPP_MODE_KEY "Mode"
#define PPP_CONNECT_RETRIES_LIMIT_KEY "ConnectRetriesLimit" #define PPP_CONNECT_RETRIES_LIMIT_KEY "ConnectRetriesLimit"
#define PPP_CONNECT_RETRY_DELAY_KEY "ConnectRetryDelay" #define PPP_CONNECT_RETRY_DELAY_KEY "ConnectRetryDelay"
#define PPP_AUTO_RECONNECT_KEY "AutoReconnect" #define PPP_AUTO_RECONNECT_KEY "AutoReconnect"
#define PPP_RECONNECT_DELAY_KEY "ReconnectDelay" #define PPP_RECONNECT_DELAY_KEY "ReconnectDelay"
#define PPP_LOAD_MODULE_KEY "LoadModule" #define PPP_LOAD_MODULE_KEY "LoadModule"
#define PPP_PROTOCOL_KEY "Protocol" #define PPP_PROTOCOL_KEY "Protocol"
@@ -35,8 +35,12 @@ typedef uint32 ppp_interface_id;
// path defines // path defines
#define PPP_MODULES_PATH NETWORK_MODULES_ROOT "ppp" #define PPP_MODULES_PATH NETWORK_MODULES_ROOT "ppp"
#define PPP_INTERFACE_SETTINGS_PATH "/boot/home/config/settings/kernel/drivers/pppidf" #define PTP_INTERFACE_SETTINGS_PATH \
// should be: /etc/ppp "/boot/home/config/settings/kernel/drivers/ptpnet"
// should be: /etc/ptpnet
#define PTP_SETTINGS_PATH \
"/boot/home/config/settings/kernel/drivers/ptpnet.settings"
// should be: /etc/ptpnet.settings
// built-in protocols // built-in protocols
#define PPP_LCP_PROTOCOL 0xC021 #define PPP_LCP_PROTOCOL 0xC021
@@ -158,7 +158,7 @@ PPPInterface::GetSettingsEntry(BEntry *entry) const
else if(!entry || strlen(Name()) == 0) else if(!entry || strlen(Name()) == 0)
return B_BAD_VALUE; return B_BAD_VALUE;
BDirectory directory(PPP_INTERFACE_SETTINGS_PATH); BDirectory directory(PTP_INTERFACE_SETTINGS_PATH);
return directory.FindEntry(Name(), entry, true); return directory.FindEntry(Name(), entry, true);
} }
@@ -133,7 +133,7 @@ PPPManager::CreateInterface(const driver_settings *settings,
/*! \brief Creates an interface with the given name and profile. /*! \brief Creates an interface with the given name and profile.
If the interface already exists its ID will be returned. If the interface already exists its ID will be returned.
Every PPP interface has a profile. By default it checks if the pppidf/profile Every PPP interface has a profile. By default it checks if the ptpnet/profile
folder contains a profile with the interface's name. Otherwise the interface's folder contains a profile with the interface's name. Otherwise the interface's
settings become its profile. This has the advantage that you can put the profile settings become its profile. This has the advantage that you can put the profile
and the settings into the same file which simplifies your PPP configuration if and the settings into the same file which simplifies your PPP configuration if