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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user