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()
: fLock("PPPManager"),
fReportLock("PPPManagerReportLock"),
fDefaultInterface(NULL),
fReportManager(fReportLock),
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
int
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");
resume_thread(app);
// XXX: What? BeOS' kernel is so &$$§$%! I cannot send anything to the
// team's main thread before the kernel sent something to it. So, we wait...
// XXX: Sending to a thread does not work immediately. So, we wait...
snooze(150000);
if(send_data(app, 0, &id, sizeof(id)) < B_OK)
@@ -895,6 +923,9 @@ PPPManager::DeleterThreadEvent()
{
LockerHelper locker(fLock);
SettingsChanged();
// TODO: Use Haiku's kernel node monitoring capabilities
// delete and remove marked interfaces
ppp_interface_entry *entry;
for(int32 index = 0; index < fEntries.CountItems(); index++) {
@@ -906,6 +937,11 @@ PPPManager::DeleterThreadEvent()
}
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
if(entry->requestThread >= 0) {
thread_info info;
@@ -913,8 +949,17 @@ PPPManager::DeleterThreadEvent()
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);
delete entry->interface;
delete entry;
fEntries.RemoveItem(index);
--index;
@@ -60,6 +60,8 @@ class PPPManager {
ppp_interface_entry *EntryFor(const char *name, int32 *saveIndex = NULL) const;
ppp_interface_entry *EntryFor(const driver_settings *settings) const;
void SettingsChanged();
ppp_interface_id NextID()
{ return (ppp_interface_id) atomic_add((int32*) &fNextID, 1); }
@@ -74,6 +76,7 @@ class PPPManager {
private:
BLocker fLock, fReportLock;
char *fDefaultInterface;
KPPPReportManager fReportManager;
TemplateList<ppp_interface_entry*> fEntries;
ppp_interface_id fNextID;
@@ -95,6 +95,7 @@ KPPPInterface::KPPPInterface(const char *name, ppp_interface_entry *entry,
fConnectRetry(0),
fConnectRetriesLimit(0),
fManager(NULL),
fConnectedSince(0),
fIdleSince(0),
fMRU(1500),
fInterfaceMTU(1498),
@@ -121,8 +122,8 @@ KPPPInterface::KPPPInterface(const char *name, ppp_interface_entry *entry,
if(name) {
// load settings from description file
char path[B_PATH_NAME_LENGTH];
sprintf(path, "pppidf/%s", name);
// XXX: TODO: change base path to "/etc/ppp" when settings API supports it
sprintf(path, "ptpnet/%s", name);
// XXX: TODO: change base path to "/etc/ptpnet"
void *handle = load_driver_settings(path);
if(!handle) {
@@ -489,6 +490,13 @@ KPPPInterface::Control(uint32 op, void *data, size_t length)
UpdateProfile();
} 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: {
if(length < sizeof(ppp_control_info) || !data)
return B_ERROR;
@@ -1373,12 +1381,22 @@ KPPPInterface::Send(struct mbuf *packet, uint16 protocolNumber)
// pass to device/children
if(!IsMultilink() || Parent()) {
// check if packet is too big for device
if((packet->m_flags & M_PKTHDR && (uint32) packet->m_pkthdr.len > MRU())
|| packet->m_len > MRU()) {
uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len :
packet->m_len;
if(length > MRU()) {
m_freem(packet);
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);
// this is normally the device, but there can be something inbetween
} else {
@@ -1488,6 +1506,9 @@ KPPPInterface::ReceiveFromDevice(struct mbuf *packet)
return B_ERROR;
}
uint32 length = packet->m_flags & M_PKTHDR ? (uint32) packet->m_pkthdr.len :
packet->m_len;
// decode ppp frame and recognize PFC
uint16 protocolNumber = *mtod(packet, uint8*);
if(protocolNumber & 1) {
@@ -1497,6 +1518,14 @@ KPPPInterface::ReceiveFromDevice(struct mbuf *packet)
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);
}
@@ -82,7 +82,7 @@ KPPPProfile::LoadSettings(const driver_settings *profile,
name = Interface().Name();
if(name) {
sprintf(path, "pppidf/profile/%s", name);
sprintf(path, "ptpnet/profile/%s", name);
void *handle = load_driver_settings(path);
if(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,
&fInterface.fID, sizeof(ppp_interface_id));
Interface().fConnectedSince = system_time();
}
}
@@ -12,6 +12,10 @@
#include <KPPPDefs.h>
#endif
#ifndef _PPP_CONTROL__H
#include <PPPControl.h>
#endif
#ifndef _K_PPP_LCP__H
#include <KPPPLCP.h>
#endif
@@ -262,6 +266,8 @@ class KPPPInterface : public KPPPLayer {
ppp_interface_module_info *fManager;
ppp_statistics fStatistics;
bigtime_t fConnectedSince;
uint32 fIdleSince, fDisconnectAfterIdleSince;
bool fUpdateIdleSince;
uint32 fMRU, fInterfaceMTU, fHeaderLength;
@@ -51,6 +51,7 @@ enum ppp_control_ops {
PPPC_SET_AUTO_RECONNECT,
PPPC_HAS_INTERFACE_SETTINGS,
PPPC_SET_PROFILE,
PPPC_GET_STATISTICS,
// handler access
PPPC_CONTROL_DEVICE = PPP_INTERFACE_OPS_START + 0xFF,
@@ -153,6 +154,8 @@ typedef struct ppp_interface_info {
uint32 connectRetry, connectRetriesLimit;
uint32 connectRetryDelay, reconnectDelay;
bigtime_t connectedSince;
// undefined if disconnected
uint32 idleSince, disconnectAfterIdleSince;
bool doesConnectOnDemand, doesAutoReconnect, hasDevice, isMultilink, hasParent;
@@ -167,6 +170,18 @@ typedef struct 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.
typedef struct ppp_device_info {
char name[PPP_HANDLER_NAME_LENGTH_LIMIT + 1];
@@ -15,13 +15,13 @@ typedef uint32 ppp_interface_id;
// settings keys
#define PPP_ASK_BEFORE_CONNECTING_KEY "AskBeforeConnecting"
#define PPP_ASK_BEFORE_CONNECTING_KEY "AskBeforeConnecting"
// userland ppp_up and preflet handle this key
#define PPP_DISONNECT_AFTER_IDLE_SINCE_KEY "DisonnectAfterIdleSince"
#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_AUTO_RECONNECT_KEY "AutoReconnect"
#define PPP_AUTO_RECONNECT_KEY "AutoReconnect"
#define PPP_RECONNECT_DELAY_KEY "ReconnectDelay"
#define PPP_LOAD_MODULE_KEY "LoadModule"
#define PPP_PROTOCOL_KEY "Protocol"
@@ -35,8 +35,12 @@ typedef uint32 ppp_interface_id;
// path defines
#define PPP_MODULES_PATH NETWORK_MODULES_ROOT "ppp"
#define PPP_INTERFACE_SETTINGS_PATH "/boot/home/config/settings/kernel/drivers/pppidf"
// should be: /etc/ppp
#define PTP_INTERFACE_SETTINGS_PATH \
"/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
#define PPP_LCP_PROTOCOL 0xC021
@@ -158,7 +158,7 @@ PPPInterface::GetSettingsEntry(BEntry *entry) const
else if(!entry || strlen(Name()) == 0)
return B_BAD_VALUE;
BDirectory directory(PPP_INTERFACE_SETTINGS_PATH);
BDirectory directory(PTP_INTERFACE_SETTINGS_PATH);
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.
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
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