diff --git a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp b/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp index eb68c7c623..80274a7965 100644 --- a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp +++ b/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp @@ -200,7 +200,10 @@ PPPManager::Output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, if(!protocol->IsEnabled() || protocol->AddressFamily() != dst->sa_family) continue; - result = protocol->Send(buf, protocol->ProtocolNumber()); + if(protocol->Flags() & PPP_INCLUDES_NCP) + result = protocol->Send(buf, protocol->ProtocolNumber() & 0x7FFF); + else + result = protocol->Send(buf, protocol->ProtocolNumber()); if(result == PPP_UNHANDLED) continue; diff --git a/src/add-ons/kernel/network/ppp/Jamfile b/src/add-ons/kernel/network/ppp/Jamfile index 0fbb7f7470..2fcc672471 100644 --- a/src/add-ons/kernel/network/ppp/Jamfile +++ b/src/add-ons/kernel/network/ppp/Jamfile @@ -1,4 +1,6 @@ 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 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/ipcp/Jamfile b/src/add-ons/kernel/network/ppp/ipcp/Jamfile new file mode 100644 index 0000000000..befef70937 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/ipcp/Jamfile @@ -0,0 +1,24 @@ +SubDir OBOS_TOP src add-ons kernel network ppp ipcp ; + +# 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 ipcp : kernel network ppp : + ipcp.cpp + Protocol.cpp + inet_addr.c +; + +SEARCH on [ FGristFiles inet_addr.c ] = [ FDirName $(OBOS_TOP) src kits network libnet ] ; + +LinkSharedOSLibs ipcp : libkernelppp.a ; + +# Installation +OBOSInstall install-networking + : /boot/home/config/add-ons/kernel/network/ppp + : ipcp ; diff --git a/src/add-ons/kernel/network/ppp/ipcp/Protocol.cpp b/src/add-ons/kernel/network/ppp/ipcp/Protocol.cpp new file mode 100644 index 0000000000..73ddc3a875 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/ipcp/Protocol.cpp @@ -0,0 +1,1301 @@ +//---------------------------------------------------------------------- +// 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 "Protocol.h" +#include +#include + +#include + +#include +#include +#include +#include + + +#ifdef _KERNEL_MODE + #define spawn_thread spawn_kernel_thread + #define printf dprintf +#elif DEBUG + #include +#endif + + +#define PPP_STATE_MACHINE_TIMEOUT 3000000 + // 3 seconds + + +IPCP::IPCP(PPPInterface& interface, driver_parameter *settings) + : PPPProtocol("IPCP", PPP_NCP_PHASE, IPCP_PROTOCOL, PPP_PROTOCOL_LEVEL, + AF_INET, 0, interface, settings, PPP_INCLUDES_NCP), + fRequestPrimaryDNS(false), + fRequestSecondaryDNS(false), + fState(PPP_INITIAL_STATE), + fID(system_time() & 0xFF), + fMaxRequest(10), + fMaxTerminate(2), + fMaxNak(5), + fRequestID(0), + fTerminateID(0), + fNextTimeout(0) +{ + // reset configurations + memset(&fLocalConfiguration, 0, sizeof(ipcp_configuration)); + memset(&fPeerConfiguration, 0, sizeof(ipcp_configuration)); + + // reset requests + memset(&fLocalRequests, 0, sizeof(ipcp_requests)); + memset(&fPeerRequests, 0, sizeof(ipcp_requests)); + + // Parse settings: + // "Local" and "Peer" describe each side's settings + for(int32 index = 0; index < settings->parameter_count; index++) { + if(!strcasecmp(settings->parameters[index].name, "Local")) + ParseSideRequests(&settings->parameters[index], PPP_LOCAL_SIDE); + else if(!strcasecmp(settings->parameters[index].name, "Peer")) + ParseSideRequests(&settings->parameters[index], PPP_PEER_SIDE); + } + + UpdateAddresses(); +} + + +IPCP::~IPCP() +{ +} + + +bool +IPCP::Up() +{ +#if DEBUG + printf("IPCP: Up() state=%d\n", State()); +#endif + + // Servers do not send a configure-request when Up() is called. They wait until + // the client requests this protocol. + if(Interface().Mode() == PPP_SERVER_MODE) + return true; + + LockerHelper locker(fLock); + + switch(State()) { + case PPP_INITIAL_STATE: + NewState(PPP_REQ_SENT_STATE); + InitializeRestartCount(); + locker.UnlockNow(); + SendConfigureRequest(); + break; + + default: + ; + } + + return true; +} + + +bool +IPCP::Down() +{ +#if DEBUG + printf("IPCP: Down() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(Interface().Phase()) { + case PPP_DOWN_PHASE: + // interface finished terminating + NewState(PPP_INITIAL_STATE); + locker.UnlockNow(); + ReportDownEvent(); + // this will also reset and update addresses + break; + +/* case PPP_TERMINATION_PHASE: + // interface is terminating + break; + + case PPP_ESTABLISHMENT_PHASE: + // interface is reconfiguring + break; +*/ + case PPP_ESTABLISHED_PHASE: + // terminate this NCP individually (block until we finished terminating) + if(State() != PPP_INITIAL_STATE && State() != PPP_CLOSING_STATE) { + NewState(PPP_CLOSING_STATE); + InitializeRestartCount(); + locker.UnlockNow(); + SendTerminateRequest(); + } + + while(State() == PPP_CLOSING_STATE) + snooze(50000); + break; + + default: + ; + } + + return true; +} + + +status_t +IPCP::Send(struct mbuf *packet, uint16 protocolNumber = IPCP_PROTOCOL) +{ + if(protocolNumber != IPCP_PROTOCOL && protocolNumber != IP_PROTOCOL) { + m_freem(packet); + return B_ERROR; + } + + return SendToNext(packet, protocolNumber); +} + + +status_t +IPCP::Receive(struct mbuf *packet, uint16 protocolNumber) +{ + if(protocolNumber == IP_PROTOCOL) + return ReceiveIPPacket(packet, protocolNumber); + + if(!packet) + return B_ERROR; + + if(protocolNumber != IPCP_PROTOCOL) + return PPP_UNHANDLED; + + ppp_lcp_packet *data = mtod(packet, ppp_lcp_packet*); + + // remove padding + int32 length = packet->m_len; + if(packet->m_flags & M_PKTHDR) + length = packet->m_pkthdr.len; + length -= ntohs(data->length); + if(length) + m_adj(packet, -length); + + if(ntohs(data->length) < 4) + return B_ERROR; + + + // packet is freed by event methods + switch(data->code) { + case PPP_CONFIGURE_REQUEST: + RCREvent(packet); + break; + + case PPP_CONFIGURE_ACK: + RCAEvent(packet); + break; + + case PPP_CONFIGURE_NAK: + case PPP_CONFIGURE_REJECT: + RCNEvent(packet); + break; + + case PPP_TERMINATE_REQUEST: + RTREvent(packet); + break; + + case PPP_TERMINATE_ACK: + RTAEvent(packet); + break; + + case PPP_CODE_REJECT: + RXJBadEvent(packet); + // we implemented the minimum requirements + break; + + default: + RUCEvent(packet); + return PPP_REJECTED; + } + + return B_OK; +} + + +status_t +IPCP::ReceiveIPPacket(struct mbuf *packet, uint16 protocolNumber) +{ + if(protocolNumber != IP_PROTOCOL) + return PPP_UNHANDLED; + + if(!packet) + return B_ERROR; + + // TODO: add VJC support (the packet would be decoded here) + + if (proto[IPPROTO_IP] && proto[IPPROTO_IP]->pr_input) { + proto[IPPROTO_IP]->pr_input(packet, 0); + return B_OK; + } else { + printf("IPCP: Error: Could not find input function for IP!\n"); + m_freem(packet); + return B_ERROR; + } +} + + +void +IPCP::Pulse() +{ + LockerHelper locker(fLock); + if(fNextTimeout == 0 || fNextTimeout > system_time()) + return; + fNextTimeout = 0; + locker.UnlockNow(); + + switch(State()) { + case PPP_CLOSING_STATE: + if(fTerminateCounter <= 0) + TOBadEvent(); + else + TOGoodEvent(); + break; + + case PPP_REQ_SENT_STATE: + case PPP_ACK_RCVD_STATE: + case PPP_ACK_SENT_STATE: + if(fRequestCounter <= 0) + TOBadEvent(); + else + TOGoodEvent(); + break; + + default: + ; + } +} + + +bool +IPCP::ParseSideRequests(driver_parameter *requests, ppp_side side) +{ + ipcp_requests *selectedRequests; + + if(side == PPP_LOCAL_SIDE) { + selectedRequests = &fLocalRequests; + fRequestPrimaryDNS = fRequestSecondaryDNS = false; + } else + selectedRequests = &fPeerRequests; + + memset(selectedRequests, 0, sizeof(ipcp_requests)); + // reset current requests + + // The following values are allowed: + // "Address" the ip address that will be suggested + // "Netmask" the netmask that should be used + // "PrimaryDNS" primary DNS server + // "SecondaryDNS" secondary DNS server + // Setting any value to 0.0.0.0 or "auto" means it should be chosen automatically. + + in_addr_t address = INADDR_ANY; + for(int32 index = 0; index < requests->parameter_count; index++) { + if(requests->parameters[index].value_count == 0) + continue; + + // all values are IP addresses, so parse the address here + if(strcasecmp(requests->parameters[index].values[0], "auto")) { + address = inet_addr(requests->parameters[index].values[0]); + if(address == INADDR_NONE) + continue; + } + + if(!strcasecmp(requests->parameters[index].name, "Address")) + selectedRequests->address = address; + else if(!strcasecmp(requests->parameters[index].name, "Netmask")) + selectedRequests->netmask = address; + else if(!strcasecmp(requests->parameters[index].name, "PrimaryDNS")) { + selectedRequests->primaryDNS = address; + if(side == PPP_LOCAL_SIDE) + fRequestPrimaryDNS = true; + } else if(!strcasecmp(requests->parameters[index].name, "SecondaryDNS")) { + selectedRequests->secondaryDNS = address; + if(side == PPP_LOCAL_SIDE) + fRequestSecondaryDNS = true; + } + } + + return true; +} + + +void +IPCP::UpdateAddresses() +{ + if(!Interface().IsUp() && !Interface().DoesDialOnDemand()) + return; + + struct sockaddr_in *address; + struct ifreq ifreq; + memset(&ifreq, 0, sizeof(ifreq)); + + address = (struct sockaddr_in*) &ifreq.ifr_addr; + address->sin_family = AF_INET; + address->sin_addr.s_addr = fLocalConfiguration.address; + in_control(NULL, SIOCSIFADDR, (caddr_t) &ifreq, Interface().Ifnet()); + + address = (struct sockaddr_in*) &ifreq.ifr_dstaddr; + address->sin_family = AF_INET; + address->sin_addr.s_addr = fPeerConfiguration.address; + in_control(NULL, SIOCSIFDSTADDR, (caddr_t) &ifreq, Interface().Ifnet()); +} + + +uint8 +IPCP::NextID() +{ + return (uint8) atomic_add(&fID, 1); +} + + +void +IPCP::NewState(ppp_state next) +{ +#if DEBUG + printf("IPCP: NewState(%d) state=%d\n", next, State()); +#endif + + // report state changes + if(State() == PPP_INITIAL_STATE && next != State()) + UpStarted(); + else if(State() == PPP_OPENED_STATE && next != State()) + DownStarted(); + + // maybe we do not need the timer anymore + if(next < PPP_CLOSING_STATE || next == PPP_OPENED_STATE) + fNextTimeout = 0; + + fState = next; +} + + +void +IPCP::TOGoodEvent() +{ +#if DEBUG + printf("IPCP: TOGoodEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(State()) { + case PPP_CLOSING_STATE: + locker.UnlockNow(); + SendTerminateRequest(); + break; + + case PPP_ACK_RCVD_STATE: + NewState(PPP_REQ_SENT_STATE); + + case PPP_REQ_SENT_STATE: + case PPP_ACK_SENT_STATE: + locker.UnlockNow(); + SendConfigureRequest(); + break; + + default: + IllegalEvent(PPP_TO_GOOD_EVENT); + } +} + + +void +IPCP::TOBadEvent() +{ +#if DEBUG + printf("IPCP: TOBadEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(State()) { + case PPP_CLOSING_STATE: + NewState(PPP_INITIAL_STATE); + locker.UnlockNow(); + ReportDownEvent(); + break; + + case PPP_REQ_SENT_STATE: + case PPP_ACK_RCVD_STATE: + case PPP_ACK_SENT_STATE: + NewState(PPP_INITIAL_STATE); + locker.UnlockNow(); + ReportUpFailedEvent(); + break; + + default: + IllegalEvent(PPP_TO_BAD_EVENT); + } +} + + +void +IPCP::RCREvent(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: RCREvent() state=%d\n", State()); +#endif + + PPPConfigurePacket request(packet); + PPPConfigurePacket nak(PPP_CONFIGURE_NAK); + PPPConfigurePacket reject(PPP_CONFIGURE_REJECT); + + // we should not use the same id as the peer + if(fID == mtod(packet, ppp_lcp_packet*)->id) + fID -= 128; + + nak.SetID(request.ID()); + reject.SetID(request.ID()); + + // parse each item + ppp_configure_item *item; + in_addr_t *requestedAddress, *wishedAddress = NULL; + for(int32 index = 0; index < request.CountItems(); index++) { + item = request.ItemAt(index); + if(!item) + continue; + + // addresses have special handling to reduce code size + switch(item->type) { + case IPCP_ADDRESSES: + // abandoned by the standard + case IPCP_ADDRESS: + wishedAddress = &fPeerRequests.address; + break; + + case IPCP_PRIMARY_DNS: + wishedAddress = &fPeerRequests.primaryDNS; + break; + + case IPCP_SECONDARY_DNS: + wishedAddress = &fPeerRequests.secondaryDNS; + break; + } + + // now parse item + switch(item->type) { + case IPCP_ADDRESSES: + // abandoned by the standard + case IPCP_ADDRESS: + case IPCP_PRIMARY_DNS: + case IPCP_SECONDARY_DNS: + if(item->length != 6) { + // the packet is invalid + m_freem(packet); + Down(); + return; + } + + requestedAddress = (in_addr_t*) item->data; + if(*wishedAddress == INADDR_ANY) { + if(*requestedAddress == INADDR_ANY) { + // we do not have an address for you + m_freem(packet); + Down(); + return; + } + } else if(*requestedAddress != *wishedAddress) { + // we do not want this address + ip_item ipItem; + ipItem.type = item->type; + ipItem.length = 6; + ipItem.address = *wishedAddress; + nak.AddItem((ppp_configure_item*) &ipItem); + } + break; + +// case IPCP_COMPRESSION_PROTOCOL: + // TODO: implement me! +// break; + + default: + reject.AddItem(item); + } + } + + // append additional values to the nak + if(!request.ItemWithType(IPCP_ADDRESS) && fPeerRequests.address == INADDR_ANY) { + // The peer did not provide us his address. Tell him to do so. + ip_item ipItem; + ipItem.type = IPCP_ADDRESS; + ipItem.length = 6; + ipItem.address = INADDR_ANY; + nak.AddItem((ppp_configure_item*) &ipItem); + } + + if(nak.CountItems() > 0) { + RCRBadEvent(nak.ToMbuf(Interface().MRU(), Interface().PacketOverhead()), NULL); + m_freem(packet); + } else if(reject.CountItems() > 0) { + RCRBadEvent(NULL, reject.ToMbuf(Interface().MRU(), + Interface().PacketOverhead())); + m_freem(packet); + } else + RCRGoodEvent(packet); +} + + +void +IPCP::RCRGoodEvent(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: RCRGoodEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(State()) { + case PPP_INITIAL_STATE: + NewState(PPP_ACK_SENT_STATE); + InitializeRestartCount(); + locker.UnlockNow(); + SendConfigureRequest(); + SendConfigureAck(packet); + break; + + case PPP_REQ_SENT_STATE: + NewState(PPP_ACK_SENT_STATE); + + case PPP_ACK_SENT_STATE: + locker.UnlockNow(); + SendConfigureAck(packet); + break; + + case PPP_ACK_RCVD_STATE: + NewState(PPP_OPENED_STATE); + locker.UnlockNow(); + SendConfigureAck(packet); + ReportUpEvent(); + break; + + case PPP_OPENED_STATE: + NewState(PPP_ACK_SENT_STATE); + locker.UnlockNow(); + SendConfigureRequest(); + SendConfigureAck(packet); + break; + + default: + m_freem(packet); + } +} + + +void +IPCP::RCRBadEvent(struct mbuf *nak, struct mbuf *reject) +{ +#if DEBUG + printf("IPCP: RCRBadEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(State()) { + case PPP_OPENED_STATE: + NewState(PPP_REQ_SENT_STATE); + locker.UnlockNow(); + SendConfigureRequest(); + + case PPP_ACK_SENT_STATE: + if(State() == PPP_ACK_SENT_STATE) + NewState(PPP_REQ_SENT_STATE); + // OPENED_STATE might have set this already + + case PPP_INITIAL_STATE: + case PPP_REQ_SENT_STATE: + case PPP_ACK_RCVD_STATE: + locker.UnlockNow(); + if(nak && ntohs(mtod(nak, ppp_lcp_packet*)->length) > 3) + SendConfigureNak(nak); + else if(reject && ntohs(mtod(reject, ppp_lcp_packet*)->length) > 3) + SendConfigureNak(reject); + return; + // prevents the nak/reject from being m_freem()'d + + default: + ; + } + + if(nak) + m_freem(nak); + if(reject) + m_freem(reject); +} + + +void +IPCP::RCAEvent(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: RCAEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + if(fRequestID != mtod(packet, ppp_lcp_packet*)->id) { + // this packet is not a reply to our request + + // TODO: log this event + m_freem(packet); + return; + } + + // parse this ack + PPPConfigurePacket ack(packet); + ppp_configure_item *item; + in_addr_t *requestedAddress, *wishedAddress = NULL, *configuredAddress = NULL; + for(int32 index = 0; index < ack.CountItems(); index++) { + item = ack.ItemAt(index); + if(!item) + continue; + + // addresses have special handling to reduce code size + switch(item->type) { + case IPCP_ADDRESSES: + // abandoned by the standard + case IPCP_ADDRESS: + wishedAddress = &fLocalRequests.address; + configuredAddress = &fLocalConfiguration.address; + break; + + case IPCP_PRIMARY_DNS: + wishedAddress = &fLocalRequests.primaryDNS; + configuredAddress = &fLocalConfiguration.primaryDNS; + break; + + case IPCP_SECONDARY_DNS: + wishedAddress = &fLocalRequests.secondaryDNS; + configuredAddress = &fLocalConfiguration.secondaryDNS; + break; + } + + // now parse item + switch(item->type) { + case IPCP_ADDRESSES: + // abandoned by the standard + case IPCP_ADDRESS: + case IPCP_PRIMARY_DNS: + case IPCP_SECONDARY_DNS: + requestedAddress = (in_addr_t*) item->data; + if((*wishedAddress == INADDR_ANY && *requestedAddress != INADDR_ANY) + || *wishedAddress == *requestedAddress) + *configuredAddress = *requestedAddress; + break; + +// case IPCP_COMPRESSION_PROTOCOL: + // TODO: implement me +// break; + + default: + ; + } + } + + // if address was not specified we should select the given one + if(!ack.ItemWithType(IPCP_ADDRESS)) + fLocalConfiguration.address = fLocalRequests.address; + + + switch(State()) { + case PPP_INITIAL_STATE: + IllegalEvent(PPP_RCA_EVENT); + break; + + case PPP_REQ_SENT_STATE: + NewState(PPP_ACK_RCVD_STATE); + InitializeRestartCount(); + break; + + case PPP_ACK_RCVD_STATE: + NewState(PPP_REQ_SENT_STATE); + locker.UnlockNow(); + SendConfigureRequest(); + break; + + case PPP_ACK_SENT_STATE: + NewState(PPP_OPENED_STATE); + InitializeRestartCount(); + locker.UnlockNow(); + ReportUpEvent(); + break; + + case PPP_OPENED_STATE: + NewState(PPP_REQ_SENT_STATE); + locker.UnlockNow(); + SendConfigureRequest(); + break; + + default: + ; + } + + m_freem(packet); +} + + +void +IPCP::RCNEvent(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: RCNEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + if(fRequestID != mtod(packet, ppp_lcp_packet*)->id) { + // this packet is not a reply to our request + + // TODO: log this event + m_freem(packet); + return; + } + + // parse this nak/reject + PPPConfigurePacket nak_reject(packet); + ppp_configure_item *item; + in_addr_t *requestedAddress; + if(nak_reject.Code() == PPP_CONFIGURE_NAK) + for(int32 index = 0; index < nak_reject.CountItems(); index++) { + item = nak_reject.ItemAt(index); + if(!item) + continue; + + switch(item->type) { + case IPCP_ADDRESSES: + // abandoned by the standard + case IPCP_ADDRESS: + if(item->length != 6) + continue; + + requestedAddress = (in_addr_t*) item->data; + if(fLocalRequests.address == INADDR_ANY + && *requestedAddress != INADDR_ANY) + fLocalConfiguration.address = *requestedAddress; + // this will be used in our next request + break; + +// case IPCP_COMPRESSION_PROTOCOL: + // TODO: implement me! +// break; + + case IPCP_PRIMARY_DNS: + if(item->length != 6) + continue; + + requestedAddress = (in_addr_t*) item->data; + if(fRequestPrimaryDNS + && fLocalRequests.primaryDNS == INADDR_ANY + && *requestedAddress != INADDR_ANY) + fLocalConfiguration.primaryDNS = *requestedAddress; + // this will be used in our next request + break; + + case IPCP_SECONDARY_DNS: + if(item->length != 6) + continue; + + requestedAddress = (in_addr_t*) item->data; + if(fRequestSecondaryDNS + && fLocalRequests.secondaryDNS == INADDR_ANY + && *requestedAddress != INADDR_ANY) + fLocalConfiguration.secondaryDNS = *requestedAddress; + // this will be used in our next request + break; + + default: + ; + } + } + else if(nak_reject.Code() == PPP_CONFIGURE_REJECT) + for(int32 index = 0; index < nak_reject.CountItems(); index++) { + item = nak_reject.ItemAt(index); + if(!item) + continue; + + switch(item->type) { +// case IPCP_COMPRESSION_PROTOCOL: + // TODO: implement me! +// break; + + default: + // DNS and addresses must be supported if we set them to auto + m_freem(packet); + Down(); + return; + } + } + + switch(State()) { + case PPP_INITIAL_STATE: + IllegalEvent(PPP_RCN_EVENT); + break; + + case PPP_REQ_SENT_STATE: + case PPP_ACK_SENT_STATE: + InitializeRestartCount(); + + case PPP_ACK_RCVD_STATE: + case PPP_OPENED_STATE: + if(State() == PPP_ACK_RCVD_STATE || State() == PPP_OPENED_STATE) + NewState(PPP_REQ_SENT_STATE); + locker.UnlockNow(); + SendConfigureRequest(); + break; + + default: + ; + } + + m_freem(packet); +} + + +void +IPCP::RTREvent(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: RTREvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + // we should not use the same ID as the peer + if(fID == mtod(packet, ppp_lcp_packet*)->id) + fID -= 128; + + switch(State()) { + case PPP_INITIAL_STATE: + IllegalEvent(PPP_RTR_EVENT); + break; + + case PPP_ACK_RCVD_STATE: + case PPP_ACK_SENT_STATE: + NewState(PPP_REQ_SENT_STATE); + + case PPP_CLOSING_STATE: + case PPP_REQ_SENT_STATE: + locker.UnlockNow(); + SendTerminateAck(packet); + return; + // do not m_freem() packet + + case PPP_OPENED_STATE: + NewState(PPP_CLOSING_STATE); + ZeroRestartCount(); + locker.UnlockNow(); + SendTerminateAck(packet); + return; + // do not m_freem() packet + + default: + ; + } + + m_freem(packet); +} + + +void +IPCP::RTAEvent(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: RTAEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + if(fTerminateID != mtod(packet, ppp_lcp_packet*)->id) { + // this packet is not a reply to our request + + // TODO: log this event + m_freem(packet); + return; + } + + switch(State()) { + case PPP_INITIAL_STATE: + IllegalEvent(PPP_RTA_EVENT); + break; + + case PPP_CLOSING_STATE: + NewState(PPP_INITIAL_STATE); + locker.UnlockNow(); + ReportDownEvent(); + break; + + case PPP_ACK_RCVD_STATE: + NewState(PPP_REQ_SENT_STATE); + break; + + case PPP_OPENED_STATE: + NewState(PPP_REQ_SENT_STATE); + locker.UnlockNow(); + SendConfigureRequest(); + break; + + default: + ; + } + + m_freem(packet); +} + + +void +IPCP::RUCEvent(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: RUCEvent() state=%d\n", State()); +#endif + + SendCodeReject(packet); +} + + +void +IPCP::RXJBadEvent(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: RXJBadEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(State()) { + case PPP_INITIAL_STATE: + IllegalEvent(PPP_RXJ_BAD_EVENT); + break; + + case PPP_CLOSING_STATE: + NewState(PPP_INITIAL_STATE); + locker.UnlockNow(); + ReportDownEvent(); + break; + + case PPP_REQ_SENT_STATE: + case PPP_ACK_RCVD_STATE: + case PPP_ACK_SENT_STATE: + NewState(PPP_INITIAL_STATE); + locker.UnlockNow(); + ReportUpFailedEvent(); + break; + + case PPP_OPENED_STATE: + NewState(PPP_CLOSING_STATE); + InitializeRestartCount(); + locker.UnlockNow(); + SendTerminateRequest(); + break; + + default: + ; + } + + m_freem(packet); +} + + +// actions +void +IPCP::IllegalEvent(ppp_event event) +{ + // TODO: update error statistics + printf("IPCP: IllegalEvent(event=%d) state=%d\n", event, State()); +} + + +void +IPCP::ReportUpFailedEvent() +{ + // reset configurations + memset(&fLocalConfiguration, 0, sizeof(ipcp_configuration)); + memset(&fPeerConfiguration, 0, sizeof(ipcp_configuration)); + + UpdateAddresses(); + + UpFailedEvent(); +} + + +void +IPCP::ReportUpEvent() +{ + UpdateAddresses(); + + UpEvent(); +} + + +void +IPCP::ReportDownEvent() +{ + // reset configurations + memset(&fLocalConfiguration, 0, sizeof(ipcp_configuration)); + memset(&fPeerConfiguration, 0, sizeof(ipcp_configuration)); + + UpdateAddresses(); + + DownEvent(); +} + + +void +IPCP::InitializeRestartCount() +{ + fRequestCounter = fMaxRequest; + fTerminateCounter = fMaxTerminate; + fNakCounter = fMaxNak; +} + + +void +IPCP::ZeroRestartCount() +{ + fRequestCounter = 0; + fTerminateCounter = 0; + fNakCounter = 0; +} + + +bool +IPCP::SendConfigureRequest() +{ +#if DEBUG + printf("IPCP: SendConfigureRequest() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + --fRequestCounter; + fNextTimeout = system_time() + PPP_STATE_MACHINE_TIMEOUT; + locker.UnlockNow(); + + PPPConfigurePacket request(PPP_CONFIGURE_REQUEST); + request.SetID(NextID()); + fRequestID = request.ID(); + ip_item ipItem; + ipItem.length = 6; + + // add address + ipItem.type = IPCP_ADDRESS; + ipItem.address = fLocalRequests.address; + request.AddItem((ppp_configure_item*) &ipItem); + + // add primary DNS (if needed) + if(fRequestPrimaryDNS && fLocalRequests.primaryDNS == INADDR_ANY) { + ipItem.type = IPCP_PRIMARY_DNS; + ipItem.address = fLocalConfiguration.primaryDNS; + // at first this is 0.0.0.0, but a nak might have set it to a correct value + request.AddItem((ppp_configure_item*) &ipItem); + } + + // add secondary DNS (if needed) + if(fRequestSecondaryDNS && fLocalRequests.primaryDNS == INADDR_ANY) { + ipItem.type = IPCP_SECONDARY_DNS; + ipItem.address = fLocalConfiguration.secondaryDNS; + // at first this is 0.0.0.0, but a nak might have set it to a correct value + request.AddItem((ppp_configure_item*) &ipItem); + } + + // TODO: add VJC support + + return Send(request.ToMbuf(Interface().MRU(), + Interface().PacketOverhead())) == B_OK; +} + + +bool +IPCP::SendConfigureAck(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: SendConfigureAck() state=%d\n", State()); +#endif + + if(!packet) + return false; + + mtod(packet, ppp_lcp_packet*)->code = PPP_CONFIGURE_ACK; + PPPConfigurePacket ack(packet); + + // verify items + ppp_configure_item *item; + in_addr_t *requestedAddress, *wishedAddress = NULL, *configuredAddress = NULL; + for(int32 index = 0; index < ack.CountItems(); index++) { + item = ack.ItemAt(index); + if(!item) + continue; + + // addresses have special handling to reduce code size + switch(item->type) { + case IPCP_ADDRESSES: + // abandoned by the standard + case IPCP_ADDRESS: + wishedAddress = &fPeerRequests.address; + configuredAddress = &fPeerConfiguration.address; + break; + + case IPCP_PRIMARY_DNS: + wishedAddress = &fPeerRequests.primaryDNS; + configuredAddress = &fPeerConfiguration.primaryDNS; + break; + + case IPCP_SECONDARY_DNS: + wishedAddress = &fPeerRequests.secondaryDNS; + configuredAddress = &fPeerConfiguration.secondaryDNS; + break; + } + + // now parse item + switch(item->type) { + case IPCP_ADDRESSES: + // abandoned by the standard + case IPCP_ADDRESS: + case IPCP_PRIMARY_DNS: + case IPCP_SECONDARY_DNS: + requestedAddress = (in_addr_t*) item->data; + if((*wishedAddress == INADDR_ANY && *requestedAddress != INADDR_ANY) + || *wishedAddress == *requestedAddress) + *configuredAddress = *requestedAddress; + break; + +// case IPCP_COMPRESSION_PROTOCOL: + // TODO: implement me! +// break; + + default: + ; + } + } + + // if address was not specified we should select the given one + if(!ack.ItemWithType(IPCP_ADDRESS)) + fPeerConfiguration.address = fPeerRequests.address; + + return Send(packet) == B_OK; +} + + +bool +IPCP::SendConfigureNak(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: SendConfigureNak() state=%d\n", State()); +#endif + + if(!packet) + return false; + + ppp_lcp_packet *nak = mtod(packet, ppp_lcp_packet*); + if(nak->code == PPP_CONFIGURE_NAK) { + if(fNakCounter == 0) { + // We sent enough naks. Let's try a reject. + nak->code = PPP_CONFIGURE_REJECT; + } else + --fNakCounter; + } + + return Send(packet) == B_OK; +} + + +bool +IPCP::SendTerminateRequest() +{ +#if DEBUG + printf("IPCP: SendTerminateRequest() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + --fTerminateCounter; + fNextTimeout = system_time() + PPP_STATE_MACHINE_TIMEOUT; + locker.UnlockNow(); + + struct mbuf *packet = m_gethdr(MT_DATA); + if(!packet) + return false; + + packet->m_pkthdr.len = packet->m_len = 4; + + // reserve some space for other protocols + packet->m_data += Interface().PacketOverhead(); + + ppp_lcp_packet *request = mtod(packet, ppp_lcp_packet*); + request->code = PPP_TERMINATE_REQUEST; + request->id = fTerminateID = NextID(); + request->length = htons(4); + + return Send(packet) == B_OK; +} + + +bool +IPCP::SendTerminateAck(struct mbuf *request = NULL) +{ +#if DEBUG + printf("IPCP: SendTerminateAck() state=%d\n", State()); +#endif + + struct mbuf *reply = request; + + ppp_lcp_packet *ack; + + if(!reply) { + reply = m_gethdr(MT_DATA); + if(!reply) + return false; + + reply->m_data += Interface().PacketOverhead(); + reply->m_pkthdr.len = reply->m_len = 4; + + ack = mtod(reply, ppp_lcp_packet*); + ack->id = NextID(); + } else + ack = mtod(reply, ppp_lcp_packet*); + + ack->code = PPP_TERMINATE_ACK; + ack->length = htons(4); + + return Send(reply) == B_OK; +} + + +bool +IPCP::SendCodeReject(struct mbuf *packet) +{ +#if DEBUG + printf("IPCP: SendCodeReject() state=%d\n", State()); +#endif + + if(!packet) + return false; + + M_PREPEND(packet, 4); + // add some space for the header + + // adjust packet if too big + int32 adjust = Interface().MRU(); + if(packet->m_flags & M_PKTHDR) { + adjust -= packet->m_pkthdr.len; + } else + adjust -= packet->m_len; + + if(adjust < 0) + m_adj(packet, adjust); + + ppp_lcp_packet *reject = mtod(packet, ppp_lcp_packet*); + reject->code = PPP_CODE_REJECT; + reject->id = NextID(); + if(packet->m_flags & M_PKTHDR) + reject->length = htons(packet->m_pkthdr.len); + else + reject->length = htons(packet->m_len); + + return Send(packet) == B_OK; +} diff --git a/src/add-ons/kernel/network/ppp/ipcp/Protocol.h b/src/add-ons/kernel/network/ppp/ipcp/Protocol.h new file mode 100644 index 0000000000..b95b5d859d --- /dev/null +++ b/src/add-ons/kernel/network/ppp/ipcp/Protocol.h @@ -0,0 +1,136 @@ +//---------------------------------------------------------------------- +// 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 PROTOCOL__H +#define PROTOCOL__H + +#include + +#include +#include + +#include + + +#define IPCP_PROTOCOL 0x8021 +#define IP_PROTOCOL 0x0021 + + +typedef struct ip_item { + uint8 type; + uint8 length; + in_addr_t address; +} ip_item; + + +enum ipcp_configure_item_codes { + IPCP_ADDRESSES = 1, + IPCP_COMPRESSION_PROTOCOL = 2, + IPCP_ADDRESS = 3, + IPCP_PRIMARY_DNS = 129, + IPCP_SECONDARY_DNS = 131 +}; + + +typedef struct ipcp_requests { + // let peer suggest value if ours equals 0.0.0.0 + in_addr_t address; + in_addr_t netmask; + // if equal 0.0.0.0 it will be chosen automatically + in_addr_t primaryDNS; + in_addr_t secondaryDNS; +} ipcp_requests; + + +// the values that were negotiated +typedef struct ipcp_configuration { + in_addr_t address; + in_addr_t primaryDNS; + in_addr_t secondaryDNS; +} ipcp_configuration; + + +extern struct protosw *proto[]; + // defined in ipcp.cpp + + +class IPCP : public PPPProtocol { + public: + IPCP(PPPInterface& interface, driver_parameter *settings); + virtual ~IPCP(); + + ppp_state State() const + { return fState; } + + virtual bool Up(); + virtual bool Down(); + + virtual status_t Send(struct mbuf *packet, + uint16 protocolNumber = IPCP_PROTOCOL); + virtual status_t Receive(struct mbuf *packet, uint16 protocolNumber); + status_t ReceiveIPPacket(struct mbuf *packet, uint16 protocolNumber); + virtual void Pulse(); + + private: + bool ParseSideRequests(driver_parameter *requests, ppp_side side); + void UpdateAddresses(); + + // for state machine + void NewState(ppp_state next); + uint8 NextID(); + // return the next id for IPCP packets + + // events + void TOGoodEvent(); + void TOBadEvent(); + void RCREvent(struct mbuf *packet); + void RCRGoodEvent(struct mbuf *packet); + void RCRBadEvent(struct mbuf *nak, struct mbuf *reject); + void RCAEvent(struct mbuf *packet); + void RCNEvent(struct mbuf *packet); + void RTREvent(struct mbuf *packet); + void RTAEvent(struct mbuf *packet); + void RUCEvent(struct mbuf *packet); + void RXJBadEvent(struct mbuf *packet); + + // actions + void IllegalEvent(ppp_event event); + void ReportUpFailedEvent(); + void ReportUpEvent(); + void ReportDownEvent(); + void InitializeRestartCount(); + void ZeroRestartCount(); + bool SendConfigureRequest(); + bool SendConfigureAck(struct mbuf *packet); + bool SendConfigureNak(struct mbuf *packet); + bool SendTerminateRequest(); + bool SendTerminateAck(struct mbuf *request = NULL); + bool SendCodeReject(struct mbuf *packet); + + private: + ipcp_configuration fLocalConfiguration, fPeerConfiguration; + ipcp_requests fLocalRequests, fPeerRequests; + + // used for local requests + bool fRequestPrimaryDNS, fRequestSecondaryDNS; + + // for state machine + ppp_state fState; + vint32 fID; + + // counters and timers + int32 fMaxRequest, fMaxTerminate, fMaxNak; + int32 fRequestCounter, fTerminateCounter, fNakCounter; + uint8 fRequestID, fTerminateID; + // the ID we used for the last configure/terminate request + bigtime_t fNextTimeout; + + BLocker fLock; +}; + + +#endif diff --git a/src/add-ons/kernel/network/ppp/ipcp/ipcp.cpp b/src/add-ons/kernel/network/ppp/ipcp/ipcp.cpp new file mode 100644 index 0000000000..493080f0c9 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/ipcp/ipcp.cpp @@ -0,0 +1,114 @@ +//---------------------------------------------------------------------- +// 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 "Protocol.h" + + +#ifdef _KERNEL_MODE + #define spawn_thread spawn_kernel_thread + #define printf dprintf +#else + #include +#endif + + +#define IPCP_MODULE_NAME "network/ppp/ipcp" + +struct protosw *proto[IPPROTO_MAX]; +struct core_module_info *core = NULL; +status_t std_ops(int32 op, ...); + +static BLocker lock; + + +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// TODO: Remove isascii() (needed for inet_aton()) when our kernel is finished! +// isascii() is not defined in the R5 kernel, thus we must define it here: +extern "C" +int +isascii(char c) +{ + return c & ~0x7f == 0; // If c is a 7 bit value. +} +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + +static +bool +add_to(PPPInterface& mainInterface, PPPInterface *subInterface, + driver_parameter *settings, ppp_module_key_type type) +{ + if(type != PPP_PROTOCOL_KEY_TYPE) + return B_ERROR; + + IPCP *ipcp; + bool success; + if(subInterface) { + ipcp = new IPCP(*subInterface, settings); + success = subInterface->AddProtocol(ipcp); + } else { + ipcp = new IPCP(mainInterface, settings); + success = mainInterface.AddProtocol(ipcp); + } + +#if DEBUG + printf("IPCP: add_to(): %s\n", + success && ipcp && ipcp->InitCheck() == B_OK ? "OK" : "ERROR"); +#endif + + return success && ipcp && ipcp->InitCheck() == B_OK; +} + + +static ppp_module_info ipcp_module = { + { + IPCP_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; + memset(proto, 0, sizeof(struct protosw*) * IPPROTO_MAX); + add_protosw(proto, NET_LAYER1); + 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*) &ipcp_module, + NULL +}; diff --git a/src/add-ons/kernel/network/ppp/pap/Jamfile b/src/add-ons/kernel/network/ppp/pap/Jamfile new file mode 100644 index 0000000000..4b94f08df6 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pap/Jamfile @@ -0,0 +1,21 @@ +SubDir OBOS_TOP src add-ons kernel network ppp pap ; + +# 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 pap : kernel network ppp : + pap.cpp + Protocol.cpp +; + +LinkSharedOSLibs pap : libkernelppp.a ; + +# Installation +OBOSInstall install-networking + : /boot/home/config/add-ons/kernel/network/ppp + : pap ; diff --git a/src/add-ons/kernel/network/ppp/pap/Protocol.cpp b/src/add-ons/kernel/network/ppp/pap/Protocol.cpp new file mode 100644 index 0000000000..778cac9987 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pap/Protocol.cpp @@ -0,0 +1,608 @@ +//---------------------------------------------------------------------- +// 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 "Protocol.h" +#include +#include + +#include + +#include +#include +#include +#include + + +#ifdef _KERNEL_MODE + #define spawn_thread spawn_kernel_thread + #define printf dprintf +#elif DEBUG + #include +#endif + + +#define PAP_TIMEOUT 3000000 + // 3 seconds + + +// PAPHandler +#define AUTHENTICATION_TYPE 0x3 +#define AUTHENTICATOR_TYPE_STRING "Authenticator" + +typedef struct authentication_item { + uint8 type; + uint8 length; + uint16 protocolNumber; +} authentication_item; + + +PAPHandler::PAPHandler(PAP& owner, PPPInterface& interface) + : PPPOptionHandler("PAP", AUTHENTICATION_TYPE, interface, NULL), + fOwner(owner) +{ +} + + +status_t +PAPHandler::AddToRequest(PPPConfigurePacket& request) +{ + // only local authenticators send requests to peer + if(Owner().Side() != PPP_PEER_SIDE) + return B_OK; + + authentication_item item; + item.type = AUTHENTICATION_TYPE; + item.length = sizeof(item); + item.protocolNumber = htons(PAP_PROTOCOL); + + request.AddItem((ppp_configure_item*) &item); + + return B_OK; +} + + +status_t +PAPHandler::ParseNak(const PPPConfigurePacket& nak) +{ + return B_OK; +} + + +status_t +PAPHandler::ParseReject(const PPPConfigurePacket& reject) +{ + return B_OK; +} + + +status_t +PAPHandler::ParseAck(const PPPConfigurePacket& ack) +{ + return B_OK; +} + + +status_t +PAPHandler::ParseRequest(const PPPConfigurePacket& request, + int32 index, PPPConfigurePacket& nak, PPPConfigurePacket& reject) +{ + // only local authenticators handle requests from peer + if(Owner().Side() != PPP_LOCAL_SIDE) + return B_OK; + + // we merely check if the values are correct + authentication_item *item = (authentication_item*) request.ItemAt(index); + if(item->type != AUTHENTICATION_TYPE + || item->length != 4 || ntohs(item->protocolNumber) != PAP_PROTOCOL) + return B_ERROR; + + return B_OK; +} + + +status_t +PAPHandler::SendingAck(const PPPConfigurePacket& ack) +{ + return B_OK; +} + + +void +PAPHandler::Reset() +{ +} + + +// PAP +PAP::PAP(PPPInterface& interface, driver_parameter *settings) + : PPPProtocol("PAP", PPP_AUTHENTICATION_PHASE, PAP_PROTOCOL, PPP_PROTOCOL_LEVEL, + AF_INET, 0, interface, settings, PPP_NO_FLAGS, + AUTHENTICATOR_TYPE_STRING, new PAPHandler(*this, interface)), + fState(INITIAL), + fID(system_time() & 0xFF), + fMaxRequest(3), + fRequestID(0), + fNextTimeout(0) +{ + fUser[0] = fPassword[0] = 0; + + ParseSettings(settings); +} + + +PAP::~PAP() +{ +} + + +status_t +PAP::InitCheck() const +{ + if(Side() != PPP_LOCAL_SIDE && Side() != PPP_PEER_SIDE) + return B_ERROR; + + return PPPProtocol::InitCheck(); +} + + +bool +PAP::Up() +{ +#if DEBUG + printf("PAP: Up() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(State()) { + case INITIAL: + if(Side() == PPP_LOCAL_SIDE) { + NewState(REQ_SENT); + InitializeRestartCount(); + locker.UnlockNow(); + SendRequest(); + } else if(Side() == PPP_PEER_SIDE) { + NewState(WAITING_FOR_REQ); + InitializeRestartCount(); + fNextTimeout = system_time() + PAP_TIMEOUT; + } else { + UpFailedEvent(); + return false; + } + break; + + default: + ; + } + + return true; +} + + +bool +PAP::Down() +{ +#if DEBUG + printf("PAP: Down() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(Interface().Phase()) { + case PPP_DOWN_PHASE: + // interface finished terminating + case PPP_ESTABLISHED_PHASE: + // terminate this NCP individually (block until we finished terminating) + NewState(INITIAL); + locker.UnlockNow(); + DownEvent(); + break; + +/* case PPP_TERMINATION_PHASE: + // interface is terminating + break; + + case PPP_ESTABLISHMENT_PHASE: + // interface is reconfiguring + break; +*/ + default: + ; + } + + return true; +} + + +status_t +PAP::Send(struct mbuf *packet, uint16 protocolNumber) +{ + // we do not encapsulate PAP packets + m_freem(packet); + return B_ERROR; +} + + +status_t +PAP::Receive(struct mbuf *packet, uint16 protocolNumber) +{ + if(!packet) + return B_ERROR; + + if(protocolNumber != PAP_PROTOCOL) + return PPP_UNHANDLED; + + ppp_lcp_packet *data = mtod(packet, ppp_lcp_packet*); + + // check if the packet is meant for us: + // only peer authenticators handle requests + if(data->code == PPP_CONFIGURE_REQUEST && Side() != PPP_PEER_SIDE) + return PPP_UNHANDLED; + // only local authenticators handle acks and naks + if((data->code == PPP_CONFIGURE_ACK || data->code == PPP_CONFIGURE_NAK) + && Side() != PPP_LOCAL_SIDE) + return PPP_UNHANDLED; + + // remove padding + int32 length = packet->m_len; + if(packet->m_flags & M_PKTHDR) + length = packet->m_pkthdr.len; + length -= ntohs(data->length); + if(length) + m_adj(packet, -length); + + if(ntohs(data->length) < 4) + return B_ERROR; + + // packet is freed by event methods + // code values are the same as for LCP (but very reduced) + 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() +{ + LockerHelper locker(fLock); + if(fNextTimeout == 0 || fNextTimeout > system_time()) + return; + fNextTimeout = 0; + locker.UnlockNow(); + + switch(State()) { + case REQ_SENT: + case WAITING_FOR_REQ: + if(fRequestCounter <= 0) + TOBadEvent(); + else + TOGoodEvent(); + break; + + default: + ; + } +} + + +bool +PAP::ParseSettings(driver_parameter *requests) +{ + memset(fUser, 0, sizeof(fUser)); + memset(fPassword, 0, sizeof(fPassword)); + + // The following values are allowed: + // "User" + // "Password" + + for(int32 index = 0; index < requests->parameter_count; index++) { + if(requests->parameters[index].value_count == 0) + continue; + + // ignore user and password if too long (255 chars at max) + if(!strcasecmp(requests->parameters[index].name, "User") + && strlen(requests->parameters[index].values[0]) < sizeof(fUser)) + strcpy(fUser, requests->parameters[index].values[0]); + else if(!strcasecmp(requests->parameters[index].name, "Password") + && strlen(requests->parameters[index].values[0]) < sizeof(fPassword)) + strcpy(fPassword, requests->parameters[index].values[0]); + } + + return true; +} + + +uint8 +PAP::NextID() +{ + return (uint8) atomic_add(&fID, 1); +} + + +void +PAP::NewState(pap_state next) +{ +#if DEBUG + printf("PAP: NewState(%d) state=%d\n", next, State()); +#endif + + // state changes + 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(); + + // maybe we do not need the timer anymore + if(next == INITIAL || next == ACCEPTED) + fNextTimeout = 0; + + fState = next; +} + + +void +PAP::TOGoodEvent() +{ +#if DEBUG + printf("PAP: TOGoodEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(State()) { + case REQ_SENT: + locker.UnlockNow(); + SendRequest(); + break; + + case WAITING_FOR_REQ: + fNextTimeout = system_time() + PAP_TIMEOUT; + break; + + default: + ; + } +} + + +void +PAP::TOBadEvent() +{ +#if DEBUG + printf("PAP: TOBadEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + switch(State()) { + case REQ_SENT: + case WAITING_FOR_REQ: + NewState(INITIAL); + locker.UnlockNow(); + UpFailedEvent(); + break; + + default: + ; + } +} + + +void +PAP::RREvent(struct mbuf *packet) +{ +#if DEBUG + printf("PAP: RREvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + ppp_lcp_packet *request = mtod(packet, ppp_lcp_packet*); + int32 length = ntohs(request->length); + uint8 *data = request->data; + uint8 *userLength = data; + uint8 *passwordLength = data + 1 + data[0]; + + // make sure the length values are all okay + if(6 + *userLength + *passwordLength > length) { + m_freem(packet); + return; + } + + char *user = (char*) userLength + 1, *password = (char*) passwordLength + 1; + + if(*userLength == strlen(fUser) && *passwordLength == strlen(fPassword) + && !strncmp(user, fUser, *userLength) + && !strncmp(password, fPassword, *passwordLength)) { + NewState(ACCEPTED); + locker.UnlockNow(); + Interface().StateMachine().PeerAuthenticationAccepted(user); + UpEvent(); + SendAck(packet); + } else { + NewState(INITIAL); + locker.UnlockNow(); + Interface().StateMachine().PeerAuthenticationDenied(user); + UpFailedEvent(); + SendNak(packet); + } +} + + +void +PAP::RAEvent(struct mbuf *packet) +{ +#if DEBUG + printf("PAP: RAEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + if(fRequestID != mtod(packet, ppp_lcp_packet*)->id) { + // this packet is not a reply to our request + + // TODO: log this event + m_freem(packet); + return; + } + + switch(State()) { + case REQ_SENT: + NewState(ACCEPTED); + locker.UnlockNow(); + Interface().StateMachine().LocalAuthenticationAccepted(fUser); + UpEvent(); + break; + + default: + ; + } + + m_freem(packet); +} + + +void +PAP::RNEvent(struct mbuf *packet) +{ +#if DEBUG + printf("PAP: RNEvent() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + + if(fRequestID != mtod(packet, ppp_lcp_packet*)->id) { + // this packet is not a reply to our request + + // TODO: log this event + m_freem(packet); + return; + } + + switch(State()) { + case REQ_SENT: + NewState(INITIAL); + locker.UnlockNow(); + Interface().StateMachine().LocalAuthenticationDenied(fUser); + UpFailedEvent(); + break; + + default: + ; + } + + m_freem(packet); +} + + +void +PAP::InitializeRestartCount() +{ + fRequestCounter = fMaxRequest; +} + + +bool +PAP::SendRequest() +{ +#if DEBUG + printf("PAP: SendRequest() state=%d\n", State()); +#endif + + LockerHelper locker(fLock); + --fRequestCounter; + fNextTimeout = system_time() + PAP_TIMEOUT; + locker.UnlockNow(); + + struct mbuf *packet = m_gethdr(MT_DATA); + if(!packet) + return false; + + packet->m_pkthdr.len = packet->m_len = 6 + strlen(fUser) + strlen(fPassword); + + // reserve some space for overhead (we are lazy and reserve too much) + packet->m_data += Interface().PacketOverhead(); + + ppp_lcp_packet *request = mtod(packet, ppp_lcp_packet*); + request->code = PPP_CONFIGURE_REQUEST; + request->id = fRequestID = NextID(); + request->length = htons(packet->m_len); + uint8 *data = request->data; + data[0] = strlen(fUser); + memcpy(data + 1, fUser, strlen(fUser)); + data[1 + data[0]] = strlen(fPassword); + memcpy(data + 2 + data[0], fUser, strlen(fUser)); + + return Interface().Send(packet, PAP_PROTOCOL) == B_OK; +} + + +bool +PAP::SendAck(struct mbuf *packet) +{ +#if DEBUG + printf("PAP: SendAck() state=%d\n", State()); +#endif + + if(!packet) + return false; + + ppp_lcp_packet *ack = mtod(packet, ppp_lcp_packet*); + ack->code = PPP_CONFIGURE_ACK; + packet->m_len = 5; + if(packet->m_flags & M_PKTHDR) + packet->m_pkthdr.len = 5; + ack->length = htons(packet->m_len); + + ack->data[0] = 0; + + return Interface().Send(packet, PAP_PROTOCOL) == B_OK; +} + + +bool +PAP::SendNak(struct mbuf *packet) +{ +#if DEBUG + printf("PAP: SendNak() state=%d\n", State()); +#endif + + if(!packet) + return false; + + ppp_lcp_packet *nak = mtod(packet, ppp_lcp_packet*); + nak->code = PPP_CONFIGURE_NAK; + packet->m_len = 5; + if(packet->m_flags & M_PKTHDR) + packet->m_pkthdr.len = 5; + nak->length = htons(packet->m_len); + + nak->data[0] = 0; + + return Interface().Send(packet, PAP_PROTOCOL) == B_OK; +} diff --git a/src/add-ons/kernel/network/ppp/pap/Protocol.h b/src/add-ons/kernel/network/ppp/pap/Protocol.h new file mode 100644 index 0000000000..717e69e41d --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pap/Protocol.h @@ -0,0 +1,114 @@ +//---------------------------------------------------------------------- +// 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 PROTOCOL__H +#define PROTOCOL__H + +#include + +#include +#include +#include + +#include + + +#define PAP_PROTOCOL 0xC023 + + +enum pap_state { + INITIAL, + REQ_SENT, + WAITING_FOR_REQ, + ACCEPTED +}; + + +class PAP; +class PAPHandler : public PPPOptionHandler { + public: + PAPHandler(PAP& owner, PPPInterface& interface); + + PAP& Owner() const + { return fOwner; } + + 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: + PAP& fOwner; +}; + + +class PAP : public PPPProtocol { + public: + PAP(PPPInterface& interface, driver_parameter *settings); + virtual ~PAP(); + + virtual status_t InitCheck() const; + + pap_state State() const + { return fState; } + + virtual bool Up(); + virtual bool Down(); + + virtual status_t Send(struct mbuf *packet, uint16 protocolNumber); + virtual status_t Receive(struct mbuf *packet, uint16 protocolNumber); + virtual void Pulse(); + + private: + bool ParseSettings(driver_parameter *settings); + + // for state machine + void NewState(pap_state next); + uint8 NextID(); + // return the next id for PAP packets + + // events + void TOGoodEvent(); + void TOBadEvent(); + void RREvent(struct mbuf *packet); + void RAEvent(struct mbuf *packet); + void RNEvent(struct mbuf *packet); + + // actions + void ReportUpFailedEvent(); + void ReportUpEvent(); + void ReportDownEvent(); + void InitializeRestartCount(); + bool SendRequest(); + bool SendAck(struct mbuf *packet); + bool SendNak(struct mbuf *packet); + + private: + char fUser[256], fPassword[256]; + + // for state machine + pap_state fState; + vint32 fID; + + // counters and timers + int32 fMaxRequest; + int32 fRequestCounter; + uint8 fRequestID; + // the ID we used for the last configure/terminate request + bigtime_t fNextTimeout; + + BLocker fLock; +}; + + +#endif diff --git a/src/add-ons/kernel/network/ppp/pap/pap.cpp b/src/add-ons/kernel/network/ppp/pap/pap.cpp new file mode 100644 index 0000000000..7167614f78 --- /dev/null +++ b/src/add-ons/kernel/network/ppp/pap/pap.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 "Protocol.h" + + +#ifdef _KERNEL_MODE + #define spawn_thread spawn_kernel_thread + #define printf dprintf +#else + #include +#endif + + +#define PAP_MODULE_NAME "network/ppp/pap" + +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(type != PPP_AUTHENTICATOR_KEY_TYPE) + return B_ERROR; + + PAP *pap; + bool success; + if(subInterface) { + pap = new PAP(*subInterface, settings); + success = subInterface->AddProtocol(pap); + } else { + pap = new PAP(mainInterface, settings); + success = mainInterface.AddProtocol(pap); + } + +#if DEBUG + printf("IPCP: add_to(): %s\n", + success && pap && pap->InitCheck() == B_OK ? "OK" : "ERROR"); +#endif + + return success && pap && pap->InitCheck() == B_OK; +} + + +static ppp_module_info pap_module = { + { + PAP_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*) &pap_module, + NULL +}; diff --git a/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp b/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp index a697d12dd3..cd375d51c4 100644 --- a/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp +++ b/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp @@ -172,7 +172,8 @@ std_ops(int32 op, ...) if(get_module(NET_CORE_MODULE_NAME, (module_info**)&core) != B_OK) return B_ERROR; - if(get_module(NET_ETHERNET_MODULE_NAME, (module_info**)ðernet) != B_OK) { + if(get_module(NET_ETHERNET_MODULE_NAME, + (module_info**) ðernet) != B_OK) { put_module(NET_CORE_MODULE_NAME); return B_ERROR; } diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/Jamfile b/src/add-ons/kernel/network/ppp/shared/libkernelppp/Jamfile index 8d412004d8..015917b325 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/Jamfile +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/Jamfile @@ -5,10 +5,6 @@ UsePrivateHeaders [ FDirName kernel ] ; UsePrivateHeaders [ FDirName kernel util ] ; UseHeaders [ FDirName $(OBOS_TOP) src add-ons kernel network ppp shared libkernelppp headers ] ; -# for kernel_cpp.cpp/h and BLocker -SEARCH_SOURCE += [ FDirName $(OBOS_TOP) src kernel core util ] ; -SEARCH_SOURCE += [ FDirName $(OBOS_TOP) src kernel core disk_device_manager ] ; - R5KernelStaticLibrary kernelppp : kernel_cpp.cpp @@ -32,3 +28,6 @@ R5KernelStaticLibrary kernelppp : _KPPPAuthenticationHandler.cpp _KPPPPFCHandler.cpp ; + +SEARCH on [ FGristFiles kernel_cpp.cpp ] = [ FDirName $(OBOS_TOP) src kernel core util ] ; +SEARCH on [ FGristFiles Locker.cpp ] = [ FDirName $(OBOS_TOP) src kernel core disk_device_manager ] ; diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPInterface.cpp b/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPInterface.cpp index 656362b7b5..01de6696b7 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPInterface.cpp +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPInterface.cpp @@ -312,6 +312,18 @@ PPPInterface::SetMRU(uint32 MRU) } +uint32 +PPPInterface::PacketOverhead() const +{ + uint32 overhead = fHeaderLength + 2; + + if(Device()) + overhead += Device()->Overhead(); + + return overhead; +} + + status_t PPPInterface::Control(uint32 op, void *data, size_t length) { @@ -1177,7 +1189,7 @@ PPPInterface::Send(struct mbuf *packet, uint16 protocolNumber) // make sure that protocol is allowed to send and everything is up if(!Device()->IsUp() || !protocol || !protocol->IsEnabled() - || !IsProtocolAllowed(*protocol)){ + || !IsProtocolAllowed(*protocol)) { m_freem(packet); return B_ERROR; } @@ -1248,6 +1260,7 @@ PPPInterface::Receive(struct mbuf *packet, uint16 protocolNumber) // Find handler and let it parse the packet. // The handler does need not be up because if we are a server // the handler might be upped by this packet. + // If authenticating we only allow authentication phase protocols. PPPProtocol *protocol = ProtocolFor(protocolNumber); for(; protocol; protocol = protocol->NextProtocol() ? diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPLCP.cpp b/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPLCP.cpp index 6e0d594fb2..a3d4be0942 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPLCP.cpp +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPLCP.cpp @@ -202,7 +202,7 @@ PPPLCP::Down() status_t -PPPLCP::Send(struct mbuf *packet, uint16 protocolNumber) +PPPLCP::Send(struct mbuf *packet, uint16 protocolNumber = PPP_LCP_PROTOCOL) { if(Target()) return Target()->Send(packet, PPP_LCP_PROTOCOL); @@ -226,9 +226,6 @@ PPPLCP::Receive(struct mbuf *packet, uint16 protocolNumber) int32 length = packet->m_len; if(packet->m_flags & M_PKTHDR) length = packet->m_pkthdr.len; -#if DEBUG - printf("LCP::Recv: len=%ld;datalen=%d\n", length, ntohs(data->length)); -#endif length -= ntohs(data->length); if(length) m_adj(packet, -length); diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPStateMachine.cpp b/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPStateMachine.cpp index f0befc5d85..4dd3db8428 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPStateMachine.cpp +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/KPPPStateMachine.cpp @@ -32,8 +32,8 @@ PPPStateMachine::PPPStateMachine(PPPInterface& interface) : fInterface(interface), fLCP(interface.LCP()), - fPhase(PPP_DOWN_PHASE), fState(PPP_INITIAL_STATE), + fPhase(PPP_DOWN_PHASE), fID(system_time() & 0xFF), fMagicNumber(0), fLocalAuthenticationStatus(PPP_NOT_AUTHENTICATED), @@ -143,6 +143,7 @@ PPPStateMachine::Reconfigure() NewState(PPP_REQ_SENT_STATE); NewPhase(PPP_ESTABLISHMENT_PHASE); + // indicates to handlers that we are reconfiguring DownProtocols(); ResetLCPHandlers(); @@ -726,8 +727,10 @@ PPPStateMachine::OpenEvent() LockerHelper locker(fLock); // reset all handlers - DownProtocols(); - ResetLCPHandlers(); + if(Phase() != PPP_ESTABLISHED_PHASE) { + DownProtocols(); + ResetLCPHandlers(); + } switch(State()) { case PPP_INITIAL_STATE: @@ -960,7 +963,6 @@ PPPStateMachine::RCRGoodEvent(struct mbuf *packet) break; case PPP_OPENED_STATE: - // tld,scr,sca/8 NewState(PPP_ACK_SENT_STATE); NewPhase(PPP_ESTABLISHMENT_PHASE); // indicates to handlers that we are reconfiguring @@ -1492,7 +1494,6 @@ PPPStateMachine::TimerEvent() default: ; } - } @@ -1572,11 +1573,13 @@ PPPStateMachine::RCREvent(struct mbuf *packet) } } - if(nak.CountItems() > 0) + if(nak.CountItems() > 0) { RCRBadEvent(nak.ToMbuf(Interface().MRU(), LCP().AdditionalOverhead()), NULL); - else if(reject.CountItems() > 0) + m_freem(packet); + } else if(reject.CountItems() > 0) { RCRBadEvent(NULL, reject.ToMbuf(Interface().MRU(), LCP().AdditionalOverhead())); - else + m_freem(packet); + } else RCRGoodEvent(packet); } @@ -1732,9 +1735,6 @@ PPPStateMachine::InitializeRestartCount() fRequestCounter = fMaxRequest; fTerminateCounter = fMaxTerminate; fNakCounter = fMaxNak; - - LockerHelper locker(fLock); - fNextTimeout = system_time() + PPP_STATE_MACHINE_TIMEOUT; } @@ -1744,9 +1744,6 @@ PPPStateMachine::ZeroRestartCount() fRequestCounter = 0; fTerminateCounter = 0; fNakCounter = 0; - - LockerHelper locker(fLock); - fNextTimeout = system_time() + PPP_STATE_MACHINE_TIMEOUT; } @@ -1884,9 +1881,9 @@ PPPStateMachine::SendTerminateAck(struct mbuf *request = NULL) ack = mtod(reply, ppp_lcp_packet*); ack->id = NextID(); - } + } else + ack = mtod(reply, ppp_lcp_packet*); - ack = mtod(reply, ppp_lcp_packet*); ack->code = PPP_TERMINATE_ACK; ack->length = htons(4); @@ -1915,15 +1912,14 @@ PPPStateMachine::SendCodeReject(struct mbuf *packet, uint16 protocolNumber, uint M_PREPEND(packet, length); // add some space for the header - int32 adjust = 0; - // adjust packet size by this value if packet is too big + // adjust packet if too big + int32 adjust = Interface().MRU(); if(packet->m_flags & M_PKTHDR) { - if((uint32) packet->m_pkthdr.len > Interface().MRU()) - adjust = Interface().MRU() - packet->m_pkthdr.len; - } else if(packet->m_len > Interface().MRU()) - adjust = Interface().MRU() - packet->m_len; + adjust -= packet->m_pkthdr.len; + } else + adjust -= packet->m_len; - if(adjust != 0) + if(adjust < 0) m_adj(packet, adjust); ppp_lcp_packet *reject = mtod(packet, ppp_lcp_packet*); @@ -1994,6 +1990,9 @@ PPPStateMachine::BringProtocolsUp() uint32 PPPStateMachine::BringPhaseUp() { + // Servers do not need to bring all protocols up. + // The client specifies which protocols he wants to go up. + LockerHelper locker(fLock); // check for phase change @@ -2004,14 +2003,23 @@ PPPStateMachine::BringPhaseUp() PPPProtocol *protocol = Interface().FirstProtocol(); for(; protocol; protocol = protocol->NextProtocol()) { if(protocol->IsEnabled() && protocol->ActivationPhase() == Phase()) { - if(protocol->IsUpRequested()) { + if(protocol->IsGoingUp() && Interface().Mode() == PPP_CLIENT_MODE) ++count; + else if(protocol->IsDown() && protocol->IsUpRequested()) { + if(Interface().Mode() == PPP_CLIENT_MODE) + ++count; + protocol->Up(); - } else if(protocol->IsGoingUp()) - ++count; + } } } + // We only wait until authentication is complete. + if(Interface().Mode() == PPP_SERVER_MODE + && (LocalAuthenticationStatus() == PPP_AUTHENTICATING + || PeerAuthenticationStatus() == PPP_AUTHENTICATING)) + ++count; + return count; } diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPMRUHandler.cpp b/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPMRUHandler.cpp index 991f0cda03..3c86f85467 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPMRUHandler.cpp +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/_KPPPMRUHandler.cpp @@ -19,7 +19,7 @@ typedef struct mru_item { uint8 type; uint8 length; uint16 MRU; -}; +} mru_item; status_t ParseRequestedItem(mru_item *item, PPPInterface& interface); 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 3fbeb151ca..b94ee1f4b4 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 @@ -88,6 +88,8 @@ class PPPInterface : public PPPLayer { uint32 InterfaceMTU() const { return fInterfaceMTU; } // this is the MRU including protocol overhead + uint32 PacketOverhead() const; + // including device and encapsulator headers virtual status_t Control(uint32 op, void *data, size_t length); diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/KPPPStateMachine.h b/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/KPPPStateMachine.h index 3c2f1cad55..ec30456019 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/KPPPStateMachine.h +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/KPPPStateMachine.h @@ -56,7 +56,10 @@ class PPPStateMachine { bool SendEchoRequest(); bool SendDiscardRequest(); - // public events + // public events: + // NOTE: Local/PeerAuthenticationAccepted/Denied MUST be called before + // Up(Failed)/DownEvent in order to allow changing the configuration of + // the next phase's protocols before they are brought up. void LocalAuthenticationRequested(); void LocalAuthenticationAccepted(const char *name); void LocalAuthenticationDenied(const char *name); @@ -143,8 +146,8 @@ class PPPStateMachine { PPPInterface& fInterface; PPPLCP& fLCP; - ppp_phase fPhase; ppp_state fState; + ppp_phase fPhase; vint32 fID; uint32 fMagicNumber; @@ -153,14 +156,14 @@ class PPPStateMachine { fPeerAuthenticationStatus; char *fLocalAuthenticationName, *fPeerAuthenticationName; - BLocker fLock; - // counters and timers int32 fMaxRequest, fMaxTerminate, fMaxNak; int32 fRequestCounter, fTerminateCounter, fNakCounter; uint8 fRequestID, fTerminateID, fEchoID; // the ID we used for the last configure/terminate/echo request bigtime_t fNextTimeout; + + BLocker fLock; }; diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/PPPDefs.h b/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/PPPDefs.h index 47b05668de..7e589e81a6 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/PPPDefs.h +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/PPPDefs.h @@ -92,13 +92,9 @@ enum { PPP_ALWAYS_ALLOWED = 0x01, // protocol may send/receive in Phase() >= PPP_ESTABLISHMENT_PHASE, // but only LCP is allowed in State() != PPP_OPENED_STATE! - PPP_NEEDS_DOWN = 0x02, - // protocol needs a Down() in addition to a Reset() to - // terminate the connection properly (losing the connection - // still results in a Reset() only) - PPP_NOT_IMPORTANT = 0x04, + PPP_NOT_IMPORTANT = 0x02, // if this protocol fails to go up we do not disconnect - PPP_INCLUDES_NCP = 0x08 + PPP_INCLUDES_NCP = 0x04, // This protocol includes the corresponding NCP protocol (e.g.: IPCP + IP). // All protocol values will also be checked against Protocol() & 0x7FFF. };