diff --git a/src/add-ons/kernel/network/ppp/Jamfile b/src/add-ons/kernel/network/ppp/Jamfile index 2fcc672471..4abacf358c 100644 --- a/src/add-ons/kernel/network/ppp/Jamfile +++ b/src/add-ons/kernel/network/ppp/Jamfile @@ -1,6 +1,7 @@ SubDir OBOS_TOP src add-ons kernel network ppp ; SubInclude OBOS_TOP src add-ons kernel network ppp ipcp ; +SubInclude OBOS_TOP src add-ons kernel network ppp modem ; SubInclude OBOS_TOP src add-ons kernel network ppp pap ; SubInclude OBOS_TOP src add-ons kernel network ppp pppoe ; SubInclude OBOS_TOP src add-ons kernel network ppp shared ; diff --git a/src/add-ons/kernel/network/ppp/TODO b/src/add-ons/kernel/network/ppp/TODO new file mode 100644 index 0000000000..d855e79582 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/TODO @@ -0,0 +1,3 @@ +- add CHAP +- add ISDN (CAPI) +- add PPP over TCP/IP (this is a virtual device that uses TCP/IP to connect to some other PPP server on the net) diff --git a/src/add-ons/kernel/network/ppp/ipcp/Protocol.cpp b/src/add-ons/kernel/network/ppp/ipcp/Protocol.cpp index a6effb7d64..4538624252 100644 --- a/src/add-ons/kernel/network/ppp/ipcp/Protocol.cpp +++ b/src/add-ons/kernel/network/ppp/ipcp/Protocol.cpp @@ -12,7 +12,6 @@ #include #include -//#include #include #include #include @@ -192,12 +191,12 @@ IPCP::Send(struct mbuf *packet, uint16 protocolNumber = IPCP_PROTOCOL) status_t IPCP::Receive(struct mbuf *packet, uint16 protocolNumber) { - if(protocolNumber == IP_PROTOCOL) - return ReceiveIPPacket(packet, protocolNumber); - if(!packet) return B_ERROR; + if(protocolNumber == IP_PROTOCOL) + return ReceiveIPPacket(packet, protocolNumber); + if(protocolNumber != IPCP_PROTOCOL) return PPP_UNHANDLED; @@ -257,9 +256,6 @@ IPCP::ReceiveIPPacket(struct mbuf *packet, uint16 protocolNumber) if(protocolNumber != IP_PROTOCOL || State() != PPP_OPENED_STATE) return PPP_UNHANDLED; - if(!packet) - return B_ERROR; - // TODO: add VJC support (the packet would be decoded here) if (gProto[IPPROTO_IP] && gProto[IPPROTO_IP]->pr_input) { diff --git a/src/add-ons/kernel/network/ppp/ipcp/TODO b/src/add-ons/kernel/network/ppp/ipcp/TODO new file mode 100644 index 0000000000..977d404321 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/ipcp/TODO @@ -0,0 +1,2 @@ +- test server mode +- add VJC compression support diff --git a/src/add-ons/kernel/network/ppp/modem/ACFCHandler.cpp b/src/add-ons/kernel/network/ppp/modem/ACFCHandler.cpp new file mode 100644 index 0000000000..098ae3139f --- /dev/null +++ b/src/add-ons/kernel/network/ppp/modem/ACFCHandler.cpp @@ -0,0 +1,121 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#include "ACFCHandler.h" + +#include + + +#define ACFC_TYPE 0x8 + + +ACFCHandler::ACFCHandler(uint32 options, PPPInterface& interface) + : PPPOptionHandler("ACFC Handler", ACFC_TYPE, interface, NULL), + fOptions(options), + fLocalState(ACFC_DISABLED), + fPeerState(ACFC_DISABLED) +{ +} + + +status_t +ACFCHandler::AddToRequest(PPPConfigurePacket& request) +{ + // is ACFC not requested or was it rejected? + if(fLocalState == ACFC_REJECTED + || (Options() & REQUEST_ACFC) == 0) + return B_OK; + + // add ACFC request + ppp_configure_item item; + item.type = ACFC_TYPE; + item.length = 2; + return request.AddItem(&item) ? B_OK : B_ERROR; +} + + +status_t +ACFCHandler::ParseNak(const PPPConfigurePacket& nak) +{ + // naks do not contain ACFC items + if(nak.ItemWithType(ACFC_TYPE)) + return B_ERROR; + + return B_OK; +} + + +status_t +ACFCHandler::ParseReject(const PPPConfigurePacket& reject) +{ + if(reject.ItemWithType(ACFC_TYPE)) { + fLocalState = ACFC_REJECTED; + + if(Options() & FORCE_ACFC_REQUEST) + return B_ERROR; + } + + return B_OK; +} + + +status_t +ACFCHandler::ParseAck(const PPPConfigurePacket& ack) +{ + if(ack.ItemWithType(ACFC_TYPE)) + fLocalState = ACFC_ACCEPTED; + else { + fLocalState = ACFC_DISABLED; + + if(Options() & FORCE_ACFC_REQUEST) + return B_ERROR; + } + + return B_OK; +} + + +status_t +ACFCHandler::ParseRequest(const PPPConfigurePacket& request, + int32 index, PPPConfigurePacket& nak, PPPConfigurePacket& reject) +{ + if(!request.ItemWithType(ACFC_TYPE)) + return B_OK; + + if((Options() & ALLOW_ACFC) == 0) { + ppp_configure_item item; + item.type = ACFC_TYPE; + item.length = 2; + return reject.AddItem(&item) ? B_OK : B_ERROR; + } + + return B_OK; +} + + +status_t +ACFCHandler::SendingAck(const PPPConfigurePacket& ack) +{ + ppp_configure_item *item = ack.ItemWithType(ACFC_TYPE); + + if(item && (Options() & ALLOW_ACFC) == 0) + return B_ERROR; + + if(item) + fPeerState = ACFC_ACCEPTED; + else + fPeerState = ACFC_DISABLED; + + return B_OK; +} + + +void +ACFCHandler::Reset() +{ + fLocalState = fPeerState = ACFC_DISABLED; +} diff --git a/src/add-ons/kernel/network/ppp/modem/ACFCHandler.h b/src/add-ons/kernel/network/ppp/modem/ACFCHandler.h new file mode 100644 index 0000000000..dc5f3dfa33 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/modem/ACFCHandler.h @@ -0,0 +1,60 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#ifndef ACFC_HANDLER__H +#define ACFC_HANDLER__H + +#include + + +// ACFC options +enum { + REQUEST_ACFC = 0x01, + // try to request ACFC (does not fail if not successful) + ALLOW_ACFC = 0x02, + // allow ACFC if other side requests it + FORCE_ACFC_REQUEST = 0x04, + // if ACFC request fails the connection attempt will terminate +}; + +enum acfc_state { + ACFC_DISABLED, + ACFC_ACCEPTED, + ACFC_REJECTED + // not used for peer state +}; + + +class ACFCHandler : public PPPOptionHandler { + public: + ACFCHandler(uint32 options, PPPInterface& interface); + + uint32 Options() const + { return fOptions; } + acfc_state LocalState() const + { return fLocalState; } + acfc_state PeerState() const + { return fPeerState; } + + virtual status_t AddToRequest(PPPConfigurePacket& request); + virtual status_t ParseNak(const PPPConfigurePacket& nak); + virtual status_t ParseReject(const PPPConfigurePacket& reject); + virtual status_t ParseAck(const PPPConfigurePacket& ack); + + virtual status_t ParseRequest(const PPPConfigurePacket& request, + int32 index, PPPConfigurePacket& nak, PPPConfigurePacket& reject); + virtual status_t SendingAck(const PPPConfigurePacket& ack); + + virtual void Reset(); + + private: + uint32 fOptions; + acfc_state fLocalState, fPeerState; +}; + + +#endif diff --git a/src/add-ons/kernel/network/ppp/modem/Jamfile b/src/add-ons/kernel/network/ppp/modem/Jamfile new file mode 100644 index 0000000000..ae3ff54da3 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/modem/Jamfile @@ -0,0 +1,22 @@ +SubDir OBOS_TOP src add-ons kernel network ppp modem ; + +# for kernel_cpp.h and BLocker +UsePrivateHeaders net ; +UsePrivateHeaders [ FDirName kernel ] ; +UsePrivateHeaders [ FDirName kernel util ] ; +UseHeaders [ FDirName $(OBOS_TOP) src add-ons kernel network ppp shared libkernelppp headers ] ; +UseHeaders [ FDirName $(OBOS_TOP) src add-ons kernel network ppp shared libkernelppp ] ; + + +R5KernelAddon modem : kernel network ppp : + modem.cpp + ModemDevice.cpp + ACFCHandler.cpp +; + +LinkSharedOSLibs modem : libkernelppp.a ; + +# Installation +OBOSInstall install-networking + : /boot/home/config/add-ons/kernel/network/ppp + : modem ; diff --git a/src/add-ons/kernel/network/ppp/modem/Modem.h b/src/add-ons/kernel/network/ppp/modem/Modem.h new file mode 100644 index 0000000000..478bf8ce32 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/modem/Modem.h @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#ifndef MODEM__H +#define MODEM__H + +#include +#include +#include + +class ModemDevice; + + +#define CONTROL_ESCAPE 0x7d +#define FLAG_SEQUENCE 0x7e +#define ALL_STATIONS 0xff +#define UI 0x03 + +#define ESCAPE_DELAY 1000000 +#define ESCAPE_SEQUENCE "+++" +#define AT_HANG_UP "ATH0" + +#define MODEM_MTU 1502 +#define PACKET_OVERHEAD 8 +#define MODEM_TIMEOUT 3000000 + // 3 seconds +#define MODEM_INTERFACE_KEY "interface" +#define MODEM_INIT_KEY "init" +#define MODEM_DIAL_KEY "dial" + +extern struct core_module_info *core; + + +#if DEBUG +// defined in ModemDevice.cpp +void dump_packet(struct mbuf *packet); +#endif // DEBUG + + +#endif diff --git a/src/add-ons/kernel/network/ppp/modem/ModemDevice.cpp b/src/add-ons/kernel/network/ppp/modem/ModemDevice.cpp new file mode 100644 index 0000000000..88dae0f032 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/modem/ModemDevice.cpp @@ -0,0 +1,531 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#include + +#include "ModemDevice.h" +#include "ACFCHandler.h" +#include "fcs.h" + +#include +#include + +// from libkernelppp +#include +#include + +#ifdef _KERNEL_MODE + #define spawn_thread spawn_kernel_thread + #define printf dprintf +#endif + + +#if DEBUG +static char sDigits[] = "0123456789ABCDEF"; +void +dump_packet(struct mbuf *packet) +{ + if(!packet) + return; + + uint8 *data = mtod(packet, uint8*); + uint8 buffer[33]; + uint8 bufferIndex = 0; + + printf("Dumping packet;len=%ld;pkthdr.len=%d\n", packet->m_len, + packet->m_flags & M_PKTHDR ? packet->m_pkthdr.len : -1); + + for(uint32 index = 0; index < packet->m_len; index++) { + buffer[bufferIndex++] = sDigits[data[index] >> 4]; + buffer[bufferIndex++] = sDigits[data[index] & 0x0F]; + if(bufferIndex == 32 || index == packet->m_len - 1) { + buffer[bufferIndex] = 0; + printf("%s\n", buffer); + bufferIndex = 0; + } + } +} +#endif + + +status_t +modem_put_line(int32 handle, const char *string, int32 length) +{ + char line[128]; + if(length > 126) + return -1; + + sprintf(line, "%s\r", string); + return write(handle, line, length + 1); +} + + +status_t +modem_get_line(int32 handle, char *string, int32 length, const char *echo) +{ + if(!string || length < 40) + return -1; + + int32 result, position = 0; + + while(position < length) { + result = read(handle, string + position, 1); + if(result < 0) + return -1; + else if(result == 1) { + if(string[position] == '\r') { + string[position] = 0; + if(!strcasecmp(string, echo)) { + position = 0; + continue; + } + + return position; + } + + position++; + } + } + + return -1; +} + + +static +status_t +worker_thread(void *data) +{ + ModemDevice *device = (ModemDevice*) data; + int32 handle = device->Handle(); + uint8 buffer[MODEM_MTU]; + + // send init string + if(modem_put_line(handle, device->InitString(), strlen(device->InitString())) < 0 + || modem_get_line(handle, (char*) buffer, sizeof(buffer), + device->InitString()) < 0 + || strcmp((char*) buffer, "OK")) { + device->FailedDialing(); + return B_ERROR; + } + + // send dial string + if(modem_put_line(handle, device->DialString(), strlen(device->DialString())) < 0 + || modem_get_line(handle, (char*) buffer, sizeof(buffer), + device->DialString()) < 0 + || strncmp((char*) buffer, "CONNECT", 7)) { + device->FailedDialing(); + return B_ERROR; + } + + if(strlen((char*) buffer) > 8) + device->SetSpeed(atoi((char*) buffer + 8)); + else + device->SetSpeed(19200); + + // TODO: authenticate if needed + + device->FinishedDialing(); + + // start decoding + int32 length = 0, position = 0; + bool inPacket = true, needsEscape = false; + + while(true) { + // ignore data if buffer is full + if(position == MODEM_MTU) + position = 0; + + length = read(handle, buffer + position, MODEM_MTU - position); + + if(length < 0 || !device->IsUp()) { + device->ConnectionLost(); + return B_ERROR; + } + + // decode the packet + for(int32 index = 0; index < length; ) { + if(buffer[position] == FLAG_SEQUENCE) { + if(inPacket && position > 0) + device->DataReceived(buffer, position); + // DataReceived() will check FCS + + length = length - index - 1; + // remaining data length + memmove(buffer, buffer + position + 1, length); + position = index = 0; + + needsEscape = false; + inPacket = true; + continue; + } + + if(buffer[position + index] < 0x20) { + ++index; + continue; + } + + if(needsEscape) { + buffer[position] = buffer[position + index] ^ 0x20; + ++position; + needsEscape = false; + } else if(buffer[position + index] == CONTROL_ESCAPE) { + ++index; + needsEscape = true; + } else { + buffer[position] = buffer[position + index]; + ++position; + } + } + } +} + + +ModemDevice::ModemDevice(PPPInterface& interface, driver_parameter *settings) + : PPPDevice("PPPoE", 0, interface, settings), + fInterfaceName(NULL), + fHandle(-1), + fWorkerThread(-1), + fOutputBytes(0), + fState(INITIAL) +{ +#if DEBUG + printf("ModemDevice: Constructor\n"); + if(!settings || !settings->parameters) + printf("ModemDevice::ctor: No settings!\n"); +#endif + + fACFC = new ACFCHandler(REQUEST_ACFC | ALLOW_ACFC, interface); + if(!interface.LCP().AddOptionHandler(fACFC)) { + fInitStatus = B_ERROR; + return; + } + + interface.SetPFCOptions(PPP_REQUEST_PFC | PPP_ALLOW_PFC); + + SetSpeed(19200); + SetMTU(MODEM_MTU); + // MTU size does not contain PPP header + + fInterfaceName = get_parameter_value(MODEM_INTERFACE_KEY, settings); + fInitString = get_parameter_value(MODEM_INIT_KEY, settings); + fDialString = get_parameter_value(MODEM_DIAL_KEY, settings); + +#if DEBUG + printf("ModemDevice::ctor: interfaceName: %s\n", interfaceName); +#endif +} + + +ModemDevice::~ModemDevice() +{ +#if DEBUG + printf("ModemDevice: Destructor\n"); +#endif +} + + +status_t +ModemDevice::InitCheck() const +{ + if(fState != INITIAL && Handle() == -1) + return B_ERROR; + + return InterfaceName() && PPPDevice::InitCheck() == B_OK ? B_OK : B_ERROR; +} + + +bool +ModemDevice::Up() +{ +#if DEBUG + printf("ModemDevice: Up()\n"); +#endif + + if(InitCheck() != B_OK) + return false; + + LockerHelper locker(fLock); + + if(IsUp()) + return true; + + fState = INITIAL; + // reset state + + // check if we are allowed to go up now (user intervention might disallow that) + if(!UpStarted()) { + CloseModem(); + DownEvent(); + return true; + // there was no error + } + + OpenModem(); + + fState = DIALING; + + if(fWorkerThread == -1) { + fWorkerThread = spawn_thread(worker_thread, "Modem: worker_thread", + B_NORMAL_PRIORITY, this); + resume_thread(fWorkerThread); + } + + return true; +} + + +bool +ModemDevice::Down() +{ +#if DEBUG + printf("ModemDevice: Down()\n"); +#endif + + if(InitCheck() != B_OK) + return false; + + LockerHelper locker(fLock); + + fState = TERMINATING; + + if(!IsUp()) { + fState = INITIAL; + CloseModem(); + DownEvent(); + return true; + } + + DownStarted(); + // this tells StateMachine that DownEvent() does not mean we lost connection + + // worker_thread will notice that we are terminating (IsUp() == false) + // ConnectionLost() will be called so we can terminate the connection there. + locker.UnlockNow(); + int32 tmp; + wait_for_thread(fWorkerThread, &tmp); + + DownEvent(); + + return true; +} + + +void +ModemDevice::SetSpeed(uint32 bps) +{ + fInputTransferRate = bps / 8; + fOutputTransferRate = (fInputTransferRate * 60) / 100; + // 60% of input transfer rate +} + + +uint32 +ModemDevice::InputTransferRate() const +{ + return fInputTransferRate; +} + + +uint32 +ModemDevice::OutputTransferRate() const +{ + return fOutputTransferRate; +} + + +uint32 +ModemDevice::CountOutputBytes() const +{ + return fOutputBytes; +} + + +void +ModemDevice::OpenModem() +{ + LockerHelper locker(fLock); + + if(Handle() >= 0) + return; + + char path[B_PATH_NAME_LENGTH]; + sprintf(path, "/dev/modem/%s", InterfaceName()); + fHandle = open(path, O_RDWR); +} + + +void +ModemDevice::CloseModem() +{ + LockerHelper locker(fLock); + + if(Handle() >= 0) + close(Handle()); + + fHandle = -1; +} + + +void +ModemDevice::FinishedDialing() +{ + LockerHelper locker(fLock); + + fOutputBytes = 0; + fState = OPENED; + UpEvent(); +} + + +void +ModemDevice::FailedDialing() +{ + LockerHelper locker(fLock); + + fWorkerThread = -1; + fState = INITIAL; + CloseModem(); + UpFailedEvent(); +} + + +void +ModemDevice::ConnectionLost() +{ + LockerHelper locker(fLock); + + // switch to command mode and disconnect + fWorkerThread = -1; + fOutputBytes = 0; + snooze(ESCAPE_DELAY); + if(write(Handle(), ESCAPE_SEQUENCE, strlen(ESCAPE_SEQUENCE)) < 0) + return; + snooze(ESCAPE_DELAY); + + modem_put_line(Handle(), AT_HANG_UP, strlen(AT_HANG_UP)); + CloseModem(); +} + + +status_t +ModemDevice::Send(struct mbuf *packet, uint16 protocolNumber = 0) +{ +#if DEBUG + printf("ModemDevice: Send()\n"); + dump_packet(packet); +#endif + + if(!packet) + return B_ERROR; + else if(InitCheck() != B_OK || protocolNumber != 0) { + m_freem(packet); + return B_ERROR; + } else if(!IsUp()) { + m_freem(packet); + return PPP_NO_CONNECTION; + } + + // we might need room for our header + if(fACFC->LocalState() != ACFC_ACCEPTED) { + M_PREPEND(packet, 2); + if(!packet) + return B_ERROR; + } + + int32 position = 0, length; + if(packet->m_flags & M_PKTHDR) + length = packet->m_pkthdr.len; + else + length = packet->m_len; + + // we need a contiguous chunk of memory + packet = m_pullup(packet, length); + if(!packet) + return B_ERROR; + + uint8 buffer[2 * (MODEM_MTU + PACKET_OVERHEAD)], *data = mtod(packet, uint8*); + + // add header + if(fACFC->LocalState() != ACFC_ACCEPTED) { + data[0] = ALL_STATIONS; + data[1] = UI; + } + + // add FCS + uint16 fcs = 0xffff; + fcs = pppfcs16(fcs, data, length); + fcs ^= 0xffff; + data[length++] = fcs & 0x00ff; + data[length++] = (fcs & 0xff00) >> 8; + + // encode packet + buffer[position++] = FLAG_SEQUENCE; + // mark beginning of packet + for(int32 index = 0; index < length; index++) { + if(data[index] < 0x20 || data[index] == FLAG_SEQUENCE + || data[index] == CONTROL_ESCAPE) { + buffer[position++] = CONTROL_ESCAPE; + buffer[position++] = data[index] ^ 0x20; + } else + buffer[position++] = data[index]; + } + buffer[position++] = FLAG_SEQUENCE; + // mark end of packet + + m_freem(packet); + + // send to modem + atomic_add((int32*) &fOutputBytes, position); + if(write(Handle(), buffer, position) < 0) + return PPP_NO_CONNECTION; + atomic_add((int32*) &fOutputBytes, -position); + + return B_OK; +} + + +status_t +ModemDevice::DataReceived(uint8 *buffer, uint32 length) +{ + // TODO: report corrupted packets to PPPInterface + + if(length < 3) + return B_ERROR; + + // check FCS + uint16 fcs = 0xffff; + fcs = pppfcs16(fcs, buffer, length - 2); + fcs ^= 0xffff; + if(buffer[length - 2] != fcs & 0x00ff || buffer[length - 1] != (fcs & 0xff00) >> 8) + return B_ERROR; + + if(buffer[0] == ALL_STATIONS && buffer[1] == UI) + buffer += 2; + + mbuf *packet = m_gethdr(MT_DATA); + packet->m_len = packet->m_pkthdr.len = length - 2; + uint8 *data = mtod(packet, uint8*); + memcpy(data, buffer, length - 2); + + return Receive(packet); +} + + +status_t +ModemDevice::Receive(struct mbuf *packet, uint16 protocolNumber = 0) +{ + // we do not need to lock because only the worker_thread calls this method + + if(!packet) + return B_ERROR; + else if(InitCheck() != B_OK || !IsUp()) { + m_freem(packet); + return B_ERROR; + } + + Interface().ReceiveFromDevice(packet); +} diff --git a/src/add-ons/kernel/network/ppp/modem/ModemDevice.h b/src/add-ons/kernel/network/ppp/modem/ModemDevice.h new file mode 100644 index 0000000000..158ee7f8ec --- /dev/null +++ b/src/add-ons/kernel/network/ppp/modem/ModemDevice.h @@ -0,0 +1,87 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#ifndef MODEM_DEVICE__H +#define MODEM_DEVICE__H + +#include "Modem.h" + +#include + + +enum modem_state { + INITIAL, + // the same as IsDown() == true + TERMINATING, + DIALING, + OPENED + // the same as IsUp() == true +}; + + +class ACFCHandler; + +class ModemDevice : public PPPDevice { + public: + ModemDevice(PPPInterface& interface, driver_parameter *settings); + virtual ~ModemDevice(); + + const char *InterfaceName() const + { return fInterfaceName; } + int32 Handle() const + { return fHandle; } + // returns file handle for modem driver + + const char *InitString() const + { return fInitString; } + const char *DialString() const + { return fDialString; } + + virtual status_t InitCheck() const; + + virtual bool Up(); + virtual bool Down(); + + void SetSpeed(uint32 bps); + virtual uint32 InputTransferRate() const; + virtual uint32 OutputTransferRate() const; + // this is around 60% of the input transfer rate + + virtual uint32 CountOutputBytes() const; + + void OpenModem(); + void CloseModem(); + + // notifications: + void FinishedDialing(); + void FailedDialing(); + void ConnectionLost(); + + virtual status_t Send(struct mbuf *packet, uint16 protocolNumber = 0); + status_t DataReceived(uint8 *buffer, uint32 length); + // this will put the data into an mbuf and call Receive() + virtual status_t Receive(struct mbuf *packet, uint16 protocolNumber = 0); + + private: + const char *fInterfaceName, *fInitString, *fDialString; + int32 fHandle; + // file handle for modem driver + + thread_id fWorkerThread; + + uint32 fInputTransferRate, fOutputTransferRate; + uint32 fOutputBytes; + + modem_state fState; + + ACFCHandler *fACFC; + + BLocker fLock; +}; + + +#endif diff --git a/src/add-ons/kernel/network/ppp/modem/TODO b/src/add-ons/kernel/network/ppp/modem/TODO new file mode 100644 index 0000000000..5c4b50d46d --- /dev/null +++ b/src/add-ons/kernel/network/ppp/modem/TODO @@ -0,0 +1,5 @@ +- get escape character from S-Register 2 (default: +) +- get escape guard time from S-Register 12 (default: 1 second) +- add support for server mode +- add ACCM support (including ACCM option handler and encoding) +- add chat login authentication (like terminal login) diff --git a/src/add-ons/kernel/network/ppp/modem/fcs.h b/src/add-ons/kernel/network/ppp/modem/fcs.h new file mode 100644 index 0000000000..876062f53e --- /dev/null +++ b/src/add-ons/kernel/network/ppp/modem/fcs.h @@ -0,0 +1,62 @@ +/*-----Lifted from RFC 1662, + PPP in HDLC-like Framing------------ + http://www.faqs.org/rfcs/rfc1662.html + */ + +/* + * u16 represents an unsigned 16-bit number. Adjust the typedef for + * your hardware. + */ + typedef uint16 u16; + + /* + * FCS lookup table as calculated by the table generator. + */ + static u16 fcstab[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + + #define PPPINITFCS16 0xffff /* Initial FCS value */ + #define PPPGOODFCS16 0xf0b8 /* Good final FCS value */ + + /* + * Calculate a new fcs given the current fcs and the new data. + */ + u16 pppfcs16(u16 fcs, unsigned char *cp, int len) + { + while (len--) + fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff]; + + return (fcs); + } diff --git a/src/add-ons/kernel/network/ppp/modem/modem.cpp b/src/add-ons/kernel/network/ppp/modem/modem.cpp new file mode 100644 index 0000000000..f48c3aaa3b --- /dev/null +++ b/src/add-ons/kernel/network/ppp/modem/modem.cpp @@ -0,0 +1,97 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de +//--------------------------------------------------------------------- + +#include +#include +#include + +#include +#include +#include + +#include "ModemDevice.h" + + +#ifdef _KERNEL_MODE + #define spawn_thread spawn_kernel_thread + #define printf dprintf +#else + #include +#endif + + +#define MODEM_MODULE_NAME "network/ppp/modem" + +struct core_module_info *core = NULL; +status_t std_ops(int32 op, ...); + + +static +bool +add_to(PPPInterface& mainInterface, PPPInterface *subInterface, + driver_parameter *settings, ppp_module_key_type type) +{ + if(mainInterface.Mode() != PPP_CLIENT_MODE || type != PPP_DEVICE_KEY_TYPE) + return B_ERROR; + + ModemDevice *device; + bool success; + if(subInterface) { + device = new ModemDevice(*subInterface, settings); + success = subInterface->SetDevice(device); + } else { + device = new ModemDevice(mainInterface, settings); + success = mainInterface.SetDevice(device); + } + +#if DEBUG + printf("Modem: add_to(): %s\n", + success && device && device->InitCheck() == B_OK ? "OK" : "ERROR"); +#endif + + return success && device && device->InitCheck() == B_OK; +} + + +static ppp_module_info modem_module = { + { + MODEM_MODULE_NAME, + 0, + std_ops + }, + NULL, + add_to +}; + + +_EXPORT +status_t +std_ops(int32 op, ...) +{ + switch(op) { + case B_MODULE_INIT: + if(get_module(NET_CORE_MODULE_NAME, (module_info**)&core) != B_OK) + return B_ERROR; + return B_OK; + + case B_MODULE_UNINIT: + put_module(NET_CORE_MODULE_NAME); + break; + + default: + return B_ERROR; + } + + return B_OK; +} + + +_EXPORT +module_info *modules[] = { + (module_info*) &modem_module, + NULL +}; diff --git a/src/add-ons/kernel/network/ppp/pap/TODO b/src/add-ons/kernel/network/ppp/pap/TODO new file mode 100644 index 0000000000..2cc99aeaba --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pap/TODO @@ -0,0 +1 @@ +- test server mode diff --git a/src/add-ons/kernel/network/ppp/pppoe/PPPoE.h b/src/add-ons/kernel/network/ppp/pppoe/PPPoE.h index cc10cc38a5..e4be725b21 100644 --- a/src/add-ons/kernel/network/ppp/pppoe/PPPoE.h +++ b/src/add-ons/kernel/network/ppp/pppoe/PPPoE.h @@ -49,8 +49,10 @@ uint32 NewHostUniq(); void add_device(PPPoEDevice *device); void remove_device(PPPoEDevice *device); +#if DEBUG // defined in PPPoEDevice.cpp void dump_packet(struct mbuf *packet); +#endif // DEBUG #endif diff --git a/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp b/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp index a8bc7be07f..beb96552c5 100644 --- a/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp +++ b/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp @@ -68,6 +68,9 @@ PPPoEDevice::PPPoEDevice(PPPInterface& interface, driver_parameter *settings) printf("PPPoEDevice::ctor: No settings!\n"); #endif + interface.SetPFCOptions(PPP_ALLOW_PFC); + // we do not want to fail just because the other side requests PFC + memset(fPeer, 0xFF, sizeof(fPeer)); SetMTU(1494); // MTU size does not contain PPP header @@ -249,7 +252,7 @@ PPPoEDevice::Down() EthernetIfnet()->output(EthernetIfnet(), packet, &destination, NULL); DownEvent(); - return false; + return true; } @@ -284,16 +287,19 @@ PPPoEDevice::Send(struct mbuf *packet, uint16 protocolNumber = 0) dump_packet(packet); #endif - if(InitCheck() != B_OK || protocolNumber != 0) { + if(!packet) + return B_ERROR; + else if(InitCheck() != B_OK || protocolNumber != 0) { m_freem(packet); return B_ERROR; - } else if(!packet) - return B_ERROR; + } LockerHelper locker(fLock); - if(!IsUp()) + if(!IsUp()) { + m_freem(packet); return PPP_NO_CONNECTION; + } uint16 length = packet->m_flags & M_PKTHDR ? packet->m_pkthdr.len : packet->m_len; @@ -332,11 +338,12 @@ PPPoEDevice::Send(struct mbuf *packet, uint16 protocolNumber = 0) status_t PPPoEDevice::Receive(struct mbuf *packet, uint16 protocolNumber = 0) { - if(InitCheck() != B_OK || IsDown()) { + if(!packet) + return B_ERROR; + else if(InitCheck() != B_OK || IsDown()) { m_freem(packet); return B_ERROR; - } else if(!packet) - return B_ERROR; + } complete_pppoe_header *completeHeader = mtod(packet, complete_pppoe_header*); if(!completeHeader) { diff --git a/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h b/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h index b0985a2a42..bf322691d1 100644 --- a/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h +++ b/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.h @@ -15,11 +15,11 @@ enum pppoe_state { INITIAL, - // the same as IsDown() + // the same as IsDown() == true PADI_SENT, PADR_SENT, OPENED - // the same as IsUp() + // the same as IsUp() == true }; diff --git a/src/add-ons/kernel/network/ppp/pppoe/TODO b/src/add-ons/kernel/network/ppp/pppoe/TODO new file mode 100644 index 0000000000..13f9f21d2d --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pppoe/TODO @@ -0,0 +1 @@ +- add support for server mode diff --git a/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp b/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp index d209e46933..cd42df6d8e 100644 --- a/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp +++ b/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp @@ -126,7 +126,7 @@ bool add_to(PPPInterface& mainInterface, PPPInterface *subInterface, driver_parameter *settings, ppp_module_key_type type) { - if(type != PPP_DEVICE_KEY_TYPE) + if(mainInterface.Mode() != PPP_CLIENT_MODE || type != PPP_DEVICE_KEY_TYPE) return B_ERROR; PPPoEDevice *device; diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPLayer.cpp b/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPLayer.cpp index a3dc2be739..0e46377fd8 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPLayer.cpp +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPLayer.cpp @@ -45,6 +45,9 @@ PPPLayer::InitCheck() const status_t PPPLayer::SendToNext(struct mbuf *packet, uint16 protocolNumber) const { + if(!packet) + return B_ERROR; + // Find the next possible handler for this packet. // Normal protocols (Level() >= PPP_PROTOCOL_LEVEL) do not encapsulate anything. if(Next()) { diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/TODO b/src/add-ons/kernel/network/ppp/shared/libkernelppp/TODO new file mode 100644 index 0000000000..4028db94a3 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/TODO @@ -0,0 +1,2 @@ +- finish support for server mode +- add callback support diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPPFCHandler.cpp b/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPPFCHandler.cpp index 6b0cad8fab..e807e19378 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPPFCHandler.cpp +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPPFCHandler.cpp @@ -26,7 +26,7 @@ status_t _PPPPFCHandler::AddToRequest(PPPConfigurePacket& request) { // is PFC not requested or was it rejected? - if(fLocalPFCState & PPP_PFC_REJECTED + if(fLocalPFCState == PPP_PFC_REJECTED || (Interface().PFCOptions() & PPP_REQUEST_PFC) == 0) return B_OK; diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/KPPPInterface.h b/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/KPPPInterface.h index 33f903f039..5613998d86 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/KPPPInterface.h +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/KPPPInterface.h @@ -146,7 +146,7 @@ class PPPInterface : public PPPLayer { // the peer PFC state says if the peer accepted a request us // i.e.: the peer might send PFC-compressed packets to us bool UseLocalPFC() const - { return LocalPFCState() & PPP_PFC_ACCEPTED; } + { return LocalPFCState() == PPP_PFC_ACCEPTED; } virtual bool Up(); // in server mode Up() listens for an incoming connection