Implemented nearly everything.

TODO:
- implement Control() methods
- write an authentication option handler
- write an MRU option handler

I will need to write the jamfile...


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4415 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Waldemar Kornewald 2003-08-30 12:40:25 +00:00
parent d72bf645f0
commit 990e20ecdf
10 changed files with 291 additions and 53 deletions

View File

@ -9,14 +9,15 @@
#define _K_PPP_CONFIGURE_PACKET__H
#include <mbuf.h>
#include <List.h>
typedef struct configure_item {
typedef struct ppp_configure_item {
uint8 type;
uint8 length;
int8 data[0];
// the data follows this structure
} configure_item;
} ppp_configure_item;
class PPPConfigurePacket {
@ -27,7 +28,7 @@ class PPPConfigurePacket {
public:
PPPConfigurePacket(uint8 code);
PPPConfigurePacket(mbuf *data);
PPPConfigurePacket(mbuf *packet);
~PPPConfigurePacket();
bool SetCode(uint8 code);
@ -39,16 +40,18 @@ class PPPConfigurePacket {
uint8 ID() const
{ return fID; }
void AddItem(const configure_item *item);
bool RemoveItem(const configure_item *item);
int32 CountItems() const;
configure_item *ItemAt(int32 index) const;
bool AddItem(const ppp_configure_item *item, int32 index = -1);
bool RemoveItem(ppp_configure_item *item);
int32 CountItems() const
{ return fItems.CountItems(); }
ppp_configure_item *ItemAt(int32 index) const;
mbuf *ToMbuf(uint32 reserve = 0, uint32 maxSize = 0);
mbuf *ToMbuf(uint32 reserve = 0);
// the user is responsible for freeing the mbuf
private:
uint8 fCode, fID;
List<ppp_configure_item*> fItems;
};

View File

@ -14,7 +14,7 @@
typedef uint32 interface_id;
// various constants
#define PPP_PULSE_RATE 750000
#define PPP_PULSE_RATE 500000
// settings keys
#define PPP_DISONNECT_AFTER_IDLE_SINCE_KEY "DisonnectAfterIdleSince"

View File

@ -53,7 +53,8 @@ class PPPDevice {
// how many bytes are waiting to be sent?
virtual status_t Send(mbuf *packet) = 0;
// this should enqueue the packet and return immediately
// This should enqueue the packet and return immediately.
// The device is responsible for freeing the packet.
status_t PassToInterface(mbuf *packet);
// This will pass the packet to the interface's queue.
// Do not call Interface::ReceiveFromDevice directly

View File

@ -196,6 +196,8 @@ class PPPInterface {
List<ppp_module_info*> fModules;
BLocker& fLock;
status_t fInitStatus;
};

View File

@ -50,6 +50,14 @@ class PPPLCP : public PPPProtocol {
uint32 AdditionalOverhead() const;
// the overhead caused by the target, the device, and the interface
virtual bool Up();
virtual bool Down();
virtual status_t Send(mbuf *packet);
virtual status_t Receive(mbuf *packet, uint16 protocol);
virtual void Pulse();
private:
List<PPPOptionHandler*> fOptionHandlers;

View File

@ -60,7 +60,7 @@ class PPPProtocol {
{ return fConnectionStatus == PPP_TERMINATION_PHASE; }
virtual status_t Send(mbuf *packet) = 0;
virtual status_t Receive(mbuf *packet) = 0;
virtual status_t Receive(mbuf *packet, uint16 protocol) = 0;
virtual void Pulse();

View File

@ -6,3 +6,133 @@
//---------------------------------------------------------------------
#include "KPPPConfigurePacket.h"
PPPConfigurePacket::PPPConfigurePacket(uint8 code)
: fCode(code)
{
}
PPPConfigurePacket::PPPConfigurePacket(mbuf *packet)
{
// decode packet
lcp_packet *data = mtod(packet, lcp_packet*);
if(!SetCode(data->code))
return;
if(data->length < 4)
return;
// there are no items (or one corrupted item)
int32 position = 0;
ppp_configure_item *item;
while(position <= data->length - 4) {
item = data->data + position;
position += item->length;
AddItem(item);
}
}
PPPConfigurePacket::~PPPConfigurePacket()
{
for(int32 index = 0; index < CountItems(); index++)
free(ItemAt(index));
}
bool
PPPConfigurePacket::SetCode(uint8 code)
{
// only configure codes are allowed!
if(code < PPP_CONFIGURE_REQUEST || code > PPP_CONFIGURE_REJECT)
return false;
fCode = code;
return true;
}
bool
PPPConfigurePacket::AddItem(const ppp_configure_item *item, int32 index = -1)
{
if(item->length < 2)
return false;
ppp_configure_item *add = malloc(item->length);
memcpy(add, item, item->length);
bool status;
if(index < 0)
status = fItems.AddItem(add);
else
status = fItems.AddItem(add, index);
if(!status) {
free(add);
return false;
}
return true;
}
bool
PPPConfigurePacket::RemoveItem(ppp_configure_item *item)
{
if(!fItems.HasItem(item))
return false;
fItems.RemoveItem(item);
free(item);
return true;
}
ppp_configure_item*
PPPConfigurePacket::ItemAt(int32 index) const
{
ppp_configure_item *item = fItems.ItemAt(index);
if(item == fItems.GetDefaultItem())
return NULL;
return item;
}
mbuf*
PPPConfigurePacket::ToMbuf(uint32 reserve = 0)
{
mbuf *packet = m_gethdr(MT_DATA);
packet->m_data += reserve;
lcp_packet *data = mtod(packet, lcp_packet*);
data->code = Code();
uint8 length = 0;
ppp_configure_item *item;
for(int32 index = 0; index < CountItems(); index++) {
item = ItemAt(index);
if(0xFF - length < item->length) {
m_freem(packet);
return NULL;
}
memcpy(data->data + length, item, item->length);
length += item->length;
}
data->length = length + 2;
packet->m_len = data->length;
return packet;
}

View File

@ -23,11 +23,8 @@
// 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
// - implement timers with support for settings next time instead of receiving timer
// events
// needed for redial:
@ -82,7 +79,7 @@ PPPInterface::PPPInterface(uint32 ID, driver_settings *settings,
if(!value)
fDisconnectAfterIdleSince = 0;
else
fDisconnectAfterIdleSince = atoi(value);
fDisconnectAfterIdleSince = atoi(value) * 1000000;
if(fDisconnectAfterIdleSince < 0)
fDisconnectAfterIdleSince = 0;
@ -111,14 +108,18 @@ PPPInterface::PPPInterface(uint32 ID, driver_settings *settings,
// auto redial is disabled by default
// load all protocols and the device
LoadModules(fSettings, 0, fSettings->parameter_count);
if(LoadModules(fSettings, 0, fSettings->parameter_count))
fInitStatus = B_OK;
else
fInitStatus = B_ERROR;
}
PPPInterface::~PPPInterface()
{
fLock.Lock();
// make sure no thread wants to call Unlock() on fLock after it is deleted
if(fLock.Lock() != B_OK)
return;;
// make sure no thread wants to call Unlock() on fLock after it is deleted
Report(PPP_DESTRUCTION_REPORT, 0, NULL, 0);
// tell all listeners that we are being destroyed
@ -127,19 +128,24 @@ PPPInterface::~PPPInterface()
stop_ifq(InQueue());
wait_for_thread(fInQueueThread, &tmp);
// TODO:
// kill (or wait for) fRedialThread
// remove our iface, so that nobody will access it:
// go down if up
// unregister from ppp_manager
// delete children/remove from parent
// destroy and remove:
// device
// protocols
// encapsulators
// option handlers
Down();
UnregisterInterface();
// put all modules (in fModules)
wait_for_thread(fRedialThread, &tmp);
while(CountChildren())
ChildAt(0)->Delete();
delete Device();
while(CountProtocols())
delete ProtocolAt(0);
while(FirstEncapsulator())
delete FirstEncapsulator();
for(int32 index = 0; index < fModules.CountItems(); index++)
put_module((module_info**) &fModules.ItemAt(index));
put_module((module_info**) &fManager);
}
@ -155,7 +161,7 @@ PPPInterface::Delete()
status_t
PPPInterface::InitCheck() const
{
if(!fSettings || !fManager)
if(!fSettings || !fManager || fInitStatus != B_OK)
return B_ERROR;
// sub-interfaces should have a device
@ -188,7 +194,7 @@ PPPInterface::Control(uint32 op, void *data, size_t length)
// add:
// - routing Control() to encapsulators/protocols/option_handlers
// (calling their Control() method)
// - adding modules in right mode
// - adding modules
// - setting AutoRedial and DialOnDemand
@ -992,8 +998,6 @@ PPPInterface::Pulse()
return;
}
StateMachine().TimerEvent();
if(Device())
Device()->Pulse();

View File

@ -8,20 +8,26 @@
#include "KPPPLCP.h"
#define PPP_PROTOCOL_OVERHEAD 2
// TODO:
// - add LCP extension handlers
PPPLCP::PPPLCP(PPPInterface& interface)
: PPPProtocol("LCP", PPP_ESTABLISHMENT_PHASE, PPP_LCP_PROTOCOL
, AF_UNSPEC, &interface, NULL, PPP_ALWAYS_ALLOWED),
: PPPProtocol("LCP", PPP_ESTABLISHMENT_PHASE, PPP_LCP_PROTOCOL,
AF_UNSPEC, &interface, NULL, PPP_ALWAYS_ALLOWED),
fTarget(NULL)
{
SetUpRequested(false);
// the state machine does everything for us
}
PPPLCP::~PPPLCP()
{
while(CountOptionHandlers())
delete OptionHandlerAt(0);
}
@ -66,7 +72,7 @@ PPPLCP::OptionHandlerAt(int32 index) const
}
uint32
PPPLCP::AdditionalOverhead const
PPPLCP::AdditionalOverhead() const
{
uint32 overhead += PPP_PROTOCOL_OVERHEAD;
@ -77,3 +83,90 @@ PPPLCP::AdditionalOverhead const
return overhead;
}
bool
PPPLCP::Up()
{
}
bool
PPPLCP::Down()
{
}
status_t
PPPLCP::Send(mbuf *packet)
{
if(!Interface())
return B_ERROR;
return Interface()->Send(packet, PPP_LCP_PROTOCOL);
}
status_t
PPPLCP::Receive(mbuf *packet, uint16 protocol)
{
if(protocol != PPP_LCP_PROTOCOL)
return PPP_UNHANDLED;
lcp_packet *data = mtod(packet, lcp_packet*);
if(ntohs(data->length) < 4)
return B_ERROR;
switch(data->code) {
case PPP_CONFIGURE_REQUEST:
StateMachine().RCREvent(packet);
break;
case PPP_CONFIGURE_ACK:
StateMachine().RCAEvent(packet);
break;
case PPP_CONFIGURE_NAK:
case PPP_CONFIGURE_REJECT:
StateMachine().RCNEvent(packet);
break;
case PPP_TERMINATE_REQUEST:
StateMachine().RTREvent(packet);
break;
case PPP_TERMINATE_ACK:
StateMachine().RTAEvent(packet);
break;
case PPP_CODE_REJECT:
StateMachine().RXJEvent(packet);
break;
case PPP_PROTOCOL_REJECT:
StateMachine().RXJEvent(packet);
break;
case PPP_ECHO_REQUEST:
StateMachine().RXREvent(packet);
break;
case PPP_ECHO_REPLY:
case PPP_DISCARD_REQUEST:
// do nothing
break;
default:
return B_ERROR;
}
return B_OK;
}
void
PPPLCP::Pulse()
{
StateMachine().TimerEvent();
}

View File

@ -10,12 +10,6 @@
#define PPP_STATE_MACHINE_TIMEOUT 3000000
// TODO:
// do not forget to reset authentication status when:
// - connection is lost
// - reconfiguring?
// - terminating
// - ...
PPPStateMachine::PPPStateMachine(PPPInterface& interface)
: fInterface(&interface), fPhase(PPP_DOWN_PHASE),
@ -23,7 +17,6 @@ PPPStateMachine::PPPStateMachine(PPPInterface& interface)
fAuthenticationStatus(PPP_NOT_AUTHENTICATED),
fPeerAuthenticationStatus(PPP_NOT_AUTHENTICATED),
fAuthenticationName(NULL), fPeerAuthenticationName(NULL),
fAuthenticatorIndex(-1), fPeerAuthenticatorIndex(-1),
fMaxTerminate(2), fMaxConfigure(10), fMaxNak(5),
fRequestID(0), fTerminateID(0), fNextTimeout(0)
{
@ -49,6 +42,7 @@ PPPStateMachine::NextID()
void
PPPStateMachine::NewState(PPP_STATE next)
{
// maybe we do not need the timer anymore
if(next < PPP_CLOSING_STATE || next == PPP_OPENED_STATE)
fNextTimeout = 0;
@ -1385,11 +1379,13 @@ void
PPPStateMachine::SendTerminateRequest()
{
mbuf *m = m_gethdr(MT_DATA);
if(!request)
if(!m)
return;
--fTerminateCounter;
m->m_len = 4;
// reserve some space for other protocols
m->m_data += LCP().AdditionalOverhead();
@ -1423,8 +1419,6 @@ PPPStateMachine::SendCodeReject(mbuf *packet, uint16 protocol, uint8 type)
else
length = 4;
M_PREPEND(packet, length + LCP().AdditionalOverhead());
int32 adjust = 0;
// adjust packet size by this value if packet is too big
if(packet->m_flags & M_PKTHDR) {
@ -1437,11 +1431,14 @@ PPPStateMachine::SendCodeReject(mbuf *packet, uint16 protocol, uint8 type)
m_adj(packet, adjust);
lcp_packet *reject = mtod(packet, lcp_packet*);
data->code = type;
data->id = NextID();
data->length = (uint16) htons(reject->m_pkthdr.len);
reject->code = type;
reject->id = NextID();
if(packet->m_flags & M_PKTHDR)
reject->length = htons(packet->m_pkthdr.len);
else
reject->length = htons(packet->m_len);
protocol = (uint16) htons(protocol);
protocol = htons(protocol);
if(type == PPP_PROTOCOL_REJECT)
memcpy(&data->data, &protocol, sizeof(protocol));