* Copyright 2003-2006, Waldemar Kornewald <wkornew@gmx.net>
* Distributed under the terms of the MIT License.
*/
#include "Protocol.h"
#include <KPPPConfigurePacket.h>
#include <KPPPInterface.h>
#include <cstring>
#include <netinet/in.h>
#include <net_buffer.h>
#include <sys/sockio.h>
static const bigtime_t kPAPTimeout = 3000000;
static const uint8 kAuthenticationType = 0x3;
static const char *kAuthenticatorTypeString = "Authenticator";
typedef struct authentication_item {
uint8 type;
uint8 length;
uint16 protocolNumber;
} _PACKED authentication_item;
PAPHandler::PAPHandler(PAP& owner, KPPPInterface& interface)
: KPPPOptionHandler("PAP", kAuthenticationType, interface, NULL),
fOwner(owner)
{
}
status_t
PAPHandler::SendingAck(const KPPPConfigurePacket& ack)
{
TRACE("%s::%s: We should activate PAP Protocol here\n", __FILE__, __func__);
return KPPPOptionHandler::SendingAck(ack);
}
status_t
PAPHandler::AddToRequest(KPPPConfigurePacket& request)
{
if (Owner().Side() != PPP_PEER_SIDE)
return B_OK;
authentication_item item;
item.type = kAuthenticationType;
item.length = sizeof(item);
item.protocolNumber = htons(PAP_PROTOCOL);
request.AddItem((ppp_configure_item*) &item);
return B_OK;
}
status_t
PAPHandler::ParseRequest(const KPPPConfigurePacket& request,
int32 index, KPPPConfigurePacket& nak, KPPPConfigurePacket& reject)
{
if (Owner().Side() != PPP_LOCAL_SIDE)
return B_OK;
authentication_item *item = (authentication_item*) request.ItemAt(index);
if (item->type != kAuthenticationType
|| item->length != 4 || ntohs(item->protocolNumber) != PAP_PROTOCOL)
return B_ERROR;
return B_OK;
}
PAP::PAP(KPPPInterface& interface, driver_parameter *settings)
: KPPPProtocol("PAP", PPP_AUTHENTICATION_PHASE, PAP_PROTOCOL, PPP_PROTOCOL_LEVEL,
AF_UNSPEC, 0, interface, settings, PPP_ALWAYS_ALLOWED,
kAuthenticatorTypeString, new PAPHandler(*this, interface)),
fState(INITIAL),
fID(system_time() & 0xFF),
fMaxRequest(3),
fRequestID(0),
fNextTimeout(0)
{
}
PAP::~PAP()
{
}
status_t
PAP::InitCheck() const
{
if (Side() != PPP_LOCAL_SIDE && Side() != PPP_PEER_SIDE)
return B_ERROR;
return KPPPProtocol::InitCheck();
}
bool
PAP::Up()
{
TRACE("PAP: Up() state=%d\n", State());
switch (State()) {
case INITIAL:
if (Side() == PPP_LOCAL_SIDE) {
NewState(REQ_SENT);
InitializeRestartCount();
SendRequest();
} else if (Side() == PPP_PEER_SIDE) {
NewState(WAITING_FOR_REQ);
InitializeRestartCount();
fNextTimeout = system_time() + kPAPTimeout;
} else {
UpFailedEvent();
return false;
}
break;
default:
;
}
return true;
}
bool
PAP::Down()
{
TRACE("PAP: Down() state=%d\n", State());
switch (Interface().Phase()) {
case PPP_DOWN_PHASE:
case PPP_ESTABLISHED_PHASE:
NewState(INITIAL);
DownEvent();
break;
// interface is terminating
break;
case PPP_ESTABLISHMENT_PHASE:
// interface is reconfiguring
break;
*/
default:
;
}
return true;
}
status_t
PAP::Send(net_buffer *packet, uint16 protocolNumber)
{
TRACE("PAP: we should not send packet!\n");
if (packet != NULL)
gBufferModule->free(packet);
return B_ERROR;
}
status_t
PAP::Receive(net_buffer *packet, uint16 protocolNumber)
{
if (!packet)
return B_ERROR;
if (protocolNumber != PAP_PROTOCOL)
return PPP_UNHANDLED;
NetBufferHeaderReader<ppp_lcp_packet> bufferheader(packet);
if (bufferheader.Status() != B_OK)
return B_ERROR;
ppp_lcp_packet &data = bufferheader.Data();
if (data.code == PPP_CONFIGURE_REQUEST && Side() != PPP_PEER_SIDE)
return PPP_UNHANDLED;
if ((data.code == PPP_CONFIGURE_ACK || data.code == PPP_CONFIGURE_NAK)
&& Side() != PPP_LOCAL_SIDE)
return PPP_UNHANDLED;
int32 length = packet->size;
length -= ntohs(data.length);
if (ntohs(data.length) < 4)
return B_ERROR;
switch (data.code) {
case PPP_CONFIGURE_REQUEST:
RREvent(packet);
break;
case PPP_CONFIGURE_ACK:
RAEvent(packet);
break;
case PPP_CONFIGURE_NAK:
RNEvent(packet);
break;
default:
return PPP_UNHANDLED;
}
return B_OK;
}
void
PAP::Pulse()
{
if (fNextTimeout == 0 || fNextTimeout > system_time())
return;
fNextTimeout = 0;
switch (State()) {
case REQ_SENT:
case WAITING_FOR_REQ:
if (fRequestCounter <= 0)
TOBadEvent();
else
TOGoodEvent();
break;
default:
;
}
}
uint8
PAP::NextID()
{
return (uint8) atomic_add(&fID, 1);
}
void
PAP::NewState(pap_state next)
{
TRACE("PAP: NewState(%d) state=%d\n", next, State());
if (State() == INITIAL && next != State()) {
if (Side() == PPP_LOCAL_SIDE)
Interface().StateMachine().LocalAuthenticationRequested();
else if (Side() == PPP_PEER_SIDE)
Interface().StateMachine().PeerAuthenticationRequested();
UpStarted();
} else if (State() == ACCEPTED && next != State())
DownStarted();
if (next == INITIAL || next == ACCEPTED)
fNextTimeout = 0;
fState = next;
}
void
PAP::TOGoodEvent()
{
TRACE("PAP: TOGoodEvent() state=%d\n", State());
switch (State()) {
case REQ_SENT:
SendRequest();
break;
case WAITING_FOR_REQ:
fNextTimeout = system_time() + kPAPTimeout;
break;
default:
;
}
}
void
PAP::TOBadEvent()
{
TRACE("PAP: TOBadEvent() state=%d\n", State());
switch (State()) {
case REQ_SENT:
case WAITING_FOR_REQ:
NewState(INITIAL);
if (State() == REQ_SENT)
Interface().StateMachine().LocalAuthenticationDenied(
Interface().Username());
else
Interface().StateMachine().PeerAuthenticationDenied(
Interface().Username());
UpFailedEvent();
break;
default:
;
}
}
void
PAP::RREvent(net_buffer *packet)
{
TRACE("PAP: RREvent() state=%d\n", State());
NetBufferHeaderReader<ppp_lcp_packet> bufferheader(packet);
if (bufferheader.Status() != B_OK)
return;
ppp_lcp_packet &request = bufferheader.Data();
int32 length = ntohs(request.length);
uint8 *data = request.data;
uint8 *userLength = data;
uint8 *passwordLength = data + 1 + data[0];
if (6 + *userLength + *passwordLength > length) {
gBufferModule->free(packet);
return;
}
char *peerUsername = (char*) userLength + 1,
*peerPassword = (char*) passwordLength + 1;
const char *username = Interface().Username(), *password = Interface().Password();
if (*userLength == strlen(username) && *passwordLength == strlen(password)
&& !strncmp(peerUsername, username, *userLength)
&& !strncmp(peerPassword, password, *passwordLength)) {
NewState(ACCEPTED);
Interface().StateMachine().PeerAuthenticationAccepted(username);
UpEvent();
SendAck(packet);
} else {
NewState(INITIAL);
Interface().StateMachine().PeerAuthenticationDenied(username);
UpFailedEvent();
SendNak(packet);
}
}
void
PAP::RAEvent(net_buffer *packet)
{
TRACE("PAP: RAEvent() state=%d\n", State());
NetBufferHeaderReader<ppp_lcp_packet> bufferheader(packet);
if (bufferheader.Status() != B_OK)
return;
ppp_lcp_packet &lcp_hdr = bufferheader.Data();
if (fRequestID != lcp_hdr.id) {
gBufferModule->free(packet);
return;
}
switch (State()) {
case REQ_SENT:
NewState(ACCEPTED);
Interface().StateMachine().LocalAuthenticationAccepted(
Interface().Username());
UpEvent();
break;
default:
;
}
gBufferModule->free(packet);
}
void
PAP::RNEvent(net_buffer *packet)
{
TRACE("PAP: RNEvent() state=%d\n", State());
NetBufferHeaderReader<ppp_lcp_packet> bufferheader(packet);
if (bufferheader.Status() != B_OK)
return;
ppp_lcp_packet &lcp_hdr = bufferheader.Data();
if (fRequestID != lcp_hdr.id) {
gBufferModule->free(packet);
return;
}
switch (State()) {
case REQ_SENT:
NewState(INITIAL);
Interface().StateMachine().LocalAuthenticationDenied(
Interface().Username());
UpFailedEvent();
break;
default:
;
}
gBufferModule->free(packet);
}
void
PAP::InitializeRestartCount()
{
fRequestCounter = fMaxRequest;
}
bool
PAP::SendRequest()
{
TRACE("PAP: SendRequest() state=%d\n", State());
--fRequestCounter;
fNextTimeout = system_time() + kPAPTimeout;
net_buffer *packet = gBufferModule->create(256);
if (!packet)
return false;
ppp_lcp_packet *request;
gBufferModule->append_size(packet, 1492, (void **)&request);
const char *username = Interface().Username(), *password = Interface().Password();
uint16 packcketLenth = 6 + strlen(username) + strlen(password);
request->code = PPP_CONFIGURE_REQUEST;
request->id = fRequestID = NextID();
request->length = htons(packcketLenth);
uint8 *data = request->data;
data[0] = strlen(username);
memcpy(data + 1, username, strlen(username));
data[1 + data[0]] = strlen(password);
memcpy(data + 2 + data[0], password, strlen(password));
gBufferModule->trim(packet, packcketLenth);
return Interface().Send(packet, PAP_PROTOCOL) == B_OK;
}
bool
PAP::SendAck(net_buffer *packet)
{
TRACE("PAP: SendAck() state=%d\n", State());
if (!packet)
return false;
NetBufferHeaderReader<ppp_lcp_packet> bufferheader(packet);
if (bufferheader.Status() != B_OK)
return false;
ppp_lcp_packet &ack = bufferheader.Data();
ack.code = PPP_CONFIGURE_ACK;
ack.length = htons(5);
ack.data[0] = 0;
gBufferModule->trim(packet, 5);
bufferheader.Sync();
return Interface().Send(packet, PAP_PROTOCOL) == B_OK;
}
bool
PAP::SendNak(net_buffer *packet)
{
ERROR("PAP: SendNak() state=%d\n", State());
if (!packet)
return false;
NetBufferHeaderReader<ppp_lcp_packet> bufferheader(packet);
if (bufferheader.Status() != B_OK)
return false;
ppp_lcp_packet &nak = bufferheader.Data();
nak.code = PPP_CONFIGURE_NAK;
nak.length = htons(5);
nak.data[0] = 0;
gBufferModule->trim(packet, 5);
return Interface().Send(packet, PAP_PROTOCOL) == B_OK;
}