184b580c4SWaldemar Kornewald /*
22f13f213SWaldemar Kornewald * Copyright 2003-2006, Waldemar Kornewald <wkornew@gmx.net>
384b580c4SWaldemar Kornewald * Distributed under the terms of the MIT License.
484b580c4SWaldemar Kornewald */
55a4503c3SWaldemar Kornewald
6e3724c38Smshlyn #include <cstdlib>
7e3724c38Smshlyn
8e3724c38Smshlyn #include <ByteOrder.h>
9e3724c38Smshlyn #include <net/if_dl.h>
10e3724c38Smshlyn #include <net_stack.h>
11*5d179107SJaroslaw Pelczar #include <arpa/inet.h>
12e3724c38Smshlyn
13e3724c38Smshlyn #include <ethernet.h>
14e3724c38Smshlyn #include <ether_driver.h>
15e3724c38Smshlyn
165a4503c3SWaldemar Kornewald #include "PPPoEDevice.h"
175a4503c3SWaldemar Kornewald #include "DiscoveryPacket.h"
185a4503c3SWaldemar Kornewald
195a4503c3SWaldemar Kornewald // from libkernelppp
205a4503c3SWaldemar Kornewald #include <settings_tools.h>
215a4503c3SWaldemar Kornewald
22e3724c38Smshlyn extern net_stack_module_info *gStackModule;
23e3724c38Smshlyn extern net_buffer_module_info *gBufferModule;
24e3724c38Smshlyn extern status_t
25e3724c38Smshlyn pppoe_input(void *cookie, net_device *_device, net_buffer *packet);
265a4503c3SWaldemar Kornewald
274e0ad752SWaldemar Kornewald #if DEBUG
2893a59056SWaldemar Kornewald static char sDigits[] = "0123456789ABCDEF";
294e0ad752SWaldemar Kornewald void
dump_packet(net_buffer * packet)30e3724c38Smshlyn dump_packet(net_buffer *packet)
314e0ad752SWaldemar Kornewald {
324e0ad752SWaldemar Kornewald if (!packet)
334e0ad752SWaldemar Kornewald return;
344e0ad752SWaldemar Kornewald
35e3724c38Smshlyn BufferHeaderReader<uint8> bufferheader(packet);
36e3724c38Smshlyn if (bufferheader.Status() != B_OK)
37e3724c38Smshlyn return;
38e3724c38Smshlyn uint8 &buffer = bufferheader.Data();
39e3724c38Smshlyn uint8 *data = &buffer;
404e0ad752SWaldemar Kornewald uint8 buffer[33];
414e0ad752SWaldemar Kornewald uint8 bufferIndex = 0;
424e0ad752SWaldemar Kornewald
4384b580c4SWaldemar Kornewald TRACE("Dumping packet;len=%ld;pkthdr.len=%d\n", packet->m_len,
444e0ad752SWaldemar Kornewald packet->m_flags & M_PKTHDR ? packet->m_pkthdr.len : -1);
454e0ad752SWaldemar Kornewald
464e0ad752SWaldemar Kornewald for (uint32 index = 0; index < packet->m_len; index++) {
4793a59056SWaldemar Kornewald buffer[bufferIndex++] = sDigits[data[index] >> 4];
4893a59056SWaldemar Kornewald buffer[bufferIndex++] = sDigits[data[index] & 0x0F];
494e0ad752SWaldemar Kornewald if (bufferIndex == 32 || index == packet->m_len - 1) {
504e0ad752SWaldemar Kornewald buffer[bufferIndex] = 0;
5184b580c4SWaldemar Kornewald TRACE("%s\n", buffer);
524e0ad752SWaldemar Kornewald bufferIndex = 0;
534e0ad752SWaldemar Kornewald }
544e0ad752SWaldemar Kornewald }
554e0ad752SWaldemar Kornewald }
56e3724c38Smshlyn
57e3724c38Smshlyn
584e0ad752SWaldemar Kornewald #endif
594e0ad752SWaldemar Kornewald
604e0ad752SWaldemar Kornewald
PPPoEDevice(KPPPInterface & interface,driver_parameter * settings)611cea3d85SWaldemar Kornewald PPPoEDevice::PPPoEDevice(KPPPInterface& interface, driver_parameter *settings)
621cea3d85SWaldemar Kornewald : KPPPDevice("PPPoE", PPPoE_HEADER_SIZE + ETHER_HDR_LEN, interface, settings),
635a4503c3SWaldemar Kornewald fEthernetIfnet(NULL),
645a4503c3SWaldemar Kornewald fSessionID(0),
655a4503c3SWaldemar Kornewald fHostUniq(NewHostUniq()),
66abf44d1aSWaldemar Kornewald fACName(NULL),
67abf44d1aSWaldemar Kornewald fServiceName(NULL),
684e0ad752SWaldemar Kornewald fAttempts(0),
695a4503c3SWaldemar Kornewald fNextTimeout(0),
702f13f213SWaldemar Kornewald fState(INITIAL)
715a4503c3SWaldemar Kornewald {
725a4503c3SWaldemar Kornewald #if DEBUG
7384b580c4SWaldemar Kornewald TRACE("PPPoEDevice: Constructor\n");
745a4503c3SWaldemar Kornewald if (!settings || !settings->parameters)
7584b580c4SWaldemar Kornewald TRACE("PPPoEDevice::ctor: No settings!\n");
765a4503c3SWaldemar Kornewald #endif
775a4503c3SWaldemar Kornewald
788dad9b1eSWaldemar Kornewald interface.SetPFCOptions(PPP_ALLOW_PFC);
798dad9b1eSWaldemar Kornewald // we do not want to fail just because the other side requests PFC
808dad9b1eSWaldemar Kornewald
815a4503c3SWaldemar Kornewald memset(fPeer, 0xFF, sizeof(fPeer));
82e3724c38Smshlyn
835a4503c3SWaldemar Kornewald SetMTU(1494);
845a4503c3SWaldemar Kornewald // MTU size does not contain PPP header
855a4503c3SWaldemar Kornewald
86e3724c38Smshlyn if (!settings)
87e3724c38Smshlyn dprintf("%s::%s: settings is NULL\n", __FILE__, __func__);
88e3724c38Smshlyn
895a4503c3SWaldemar Kornewald // find ethernet device
90e3724c38Smshlyn finterfaceName = get_parameter_value(PPPoE_INTERFACE_KEY, settings);
91e3724c38Smshlyn TRACE("%s::%s: finterfaceName is %s\n", __FILE__, __func__,
92e3724c38Smshlyn finterfaceName ? finterfaceName : "NULL");
935a483e4dSWaldemar Kornewald
945a483e4dSWaldemar Kornewald fACName = get_parameter_value(PPPoE_AC_NAME_KEY, settings);
95e3724c38Smshlyn TRACE("fACName is %s\n", fACName ? fACName : "NULL");
965a4503c3SWaldemar Kornewald
97e3724c38Smshlyn fServiceName = get_parameter_value(PPPoE_SERVICE_NAME_KEY, settings);
98e3724c38Smshlyn TRACE("fServiceName is %s\n", fServiceName ? fServiceName : "NULL");
99e3724c38Smshlyn
100e3724c38Smshlyn // fEthernetIfnet = FindPPPoEInterface(interfaceName);
1015a4503c3SWaldemar Kornewald
1025a4503c3SWaldemar Kornewald #if DEBUG
1035a4503c3SWaldemar Kornewald if (!fEthernetIfnet)
10484b580c4SWaldemar Kornewald TRACE("PPPoEDevice::ctor: could not find ethernet interface\n");
105e3724c38Smshlyn else
106e3724c38Smshlyn TRACE("%s::%s: Find Ethernet device", __FILE__, __func__);
1075a4503c3SWaldemar Kornewald #endif
1085a4503c3SWaldemar Kornewald }
1095a4503c3SWaldemar Kornewald
1105a4503c3SWaldemar Kornewald
1115a4503c3SWaldemar Kornewald status_t
InitCheck() const1125a4503c3SWaldemar Kornewald PPPoEDevice::InitCheck() const
1135a4503c3SWaldemar Kornewald {
114e3724c38Smshlyn if (KPPPDevice::InitCheck() != B_OK)
115e3724c38Smshlyn dprintf("%s::%s: KPPPDevice::InitCheck() has error\n", __FILE__, __func__);
116e3724c38Smshlyn
117e3724c38Smshlyn return KPPPDevice::InitCheck() == B_OK ? B_OK : B_ERROR;
1185a4503c3SWaldemar Kornewald }
1195a4503c3SWaldemar Kornewald
1205a4503c3SWaldemar Kornewald
1215a4503c3SWaldemar Kornewald bool
Up()1225a4503c3SWaldemar Kornewald PPPoEDevice::Up()
1235a4503c3SWaldemar Kornewald {
12484b580c4SWaldemar Kornewald TRACE("PPPoEDevice: Up()\n");
1255a4503c3SWaldemar Kornewald
1265a4503c3SWaldemar Kornewald if (InitCheck() != B_OK)
1275a4503c3SWaldemar Kornewald return false;
1285a4503c3SWaldemar Kornewald
1295a4503c3SWaldemar Kornewald if (IsUp())
1305a4503c3SWaldemar Kornewald return true;
1315a4503c3SWaldemar Kornewald
132e3724c38Smshlyn fEthernetIfnet = FindPPPoEInterface(finterfaceName);
133e3724c38Smshlyn
134e3724c38Smshlyn if (fEthernetIfnet == NULL) {
135e3724c38Smshlyn dprintf("%s::%s: fEthernetIfnet %s not found\n", __FILE__, __func__, finterfaceName);
136e3724c38Smshlyn return false;
137e3724c38Smshlyn }
138e3724c38Smshlyn
139e3724c38Smshlyn memcpy(fEtherAddr, fEthernetIfnet->address.data, ETHER_ADDRESS_LENGTH);
140e3724c38Smshlyn dprintf("ppp's corresponding addr is %02x:%02x:%02x:%02x:%02x:%02x\n",
141e3724c38Smshlyn fEtherAddr[0], fEtherAddr[1], fEtherAddr[2], fEtherAddr[3],
142e3724c38Smshlyn fEtherAddr[4], fEtherAddr[5]);
143e3724c38Smshlyn
144e3724c38Smshlyn if (fEthernetIfnet->module == NULL) {
145e3724c38Smshlyn dprintf("%s::%s: fEthernetIfnet->module not found\n", __FILE__,
146e3724c38Smshlyn __func__);
147e3724c38Smshlyn return false;
148e3724c38Smshlyn }
149e3724c38Smshlyn
1502f13f213SWaldemar Kornewald add_device(this);
1512f13f213SWaldemar Kornewald
1524e0ad752SWaldemar Kornewald fState = INITIAL;
1534e0ad752SWaldemar Kornewald // reset state
1544e0ad752SWaldemar Kornewald
1554e0ad752SWaldemar Kornewald if (fAttempts > PPPoE_MAX_ATTEMPTS) {
1564e0ad752SWaldemar Kornewald fAttempts = 0;
1574e0ad752SWaldemar Kornewald return false;
1584e0ad752SWaldemar Kornewald }
1594e0ad752SWaldemar Kornewald
1604e0ad752SWaldemar Kornewald ++fAttempts;
1615a4503c3SWaldemar Kornewald // reset connection settings
1625a4503c3SWaldemar Kornewald memset(fPeer, 0xFF, sizeof(fPeer));
1635a4503c3SWaldemar Kornewald
1645a4503c3SWaldemar Kornewald // create PADI
1655a4503c3SWaldemar Kornewald DiscoveryPacket discovery(PADI);
1665a483e4dSWaldemar Kornewald if (ServiceName())
1675a483e4dSWaldemar Kornewald discovery.AddTag(SERVICE_NAME, ServiceName(), strlen(ServiceName()));
1685a4503c3SWaldemar Kornewald else
1695a483e4dSWaldemar Kornewald discovery.AddTag(SERVICE_NAME, NULL, 0);
1705a483e4dSWaldemar Kornewald discovery.AddTag(HOST_UNIQ, &fHostUniq, sizeof(fHostUniq));
1715a483e4dSWaldemar Kornewald discovery.AddTag(END_OF_LIST, NULL, 0);
1725a4503c3SWaldemar Kornewald
1735a4503c3SWaldemar Kornewald // set up PPP header
174e3724c38Smshlyn net_buffer *packet = discovery.ToNetBuffer(MTU());
1755a4503c3SWaldemar Kornewald if (!packet)
1765a4503c3SWaldemar Kornewald return false;
1775a4503c3SWaldemar Kornewald
178e3724c38Smshlyn // create ether header
179e3724c38Smshlyn NetBufferPrepend<ether_header> ethernetHeader(packet);
180e3724c38Smshlyn if (ethernetHeader.Status() != B_OK)
181e3724c38Smshlyn return false;
182e3724c38Smshlyn ether_header &header = ethernetHeader.Data();
183e3724c38Smshlyn
184e3724c38Smshlyn memset(header.destination, 0xff, ETHER_ADDRESS_LENGTH);
185e3724c38Smshlyn memcpy(header.source, fEtherAddr, ETHER_ADDRESS_LENGTH);
186e3724c38Smshlyn header.type = htons(ETHER_TYPE_PPPOE_DISCOVERY);
187e3724c38Smshlyn ethernetHeader.Sync();
1885a4503c3SWaldemar Kornewald // raw packet with ethernet header
1895a4503c3SWaldemar Kornewald
1905a4503c3SWaldemar Kornewald // check if we are allowed to go up now (user intervention might disallow that)
1914e0ad752SWaldemar Kornewald if (fAttempts > 0 && !UpStarted()) {
1924e0ad752SWaldemar Kornewald fAttempts = 0;
1932f13f213SWaldemar Kornewald remove_device(this);
1945a4503c3SWaldemar Kornewald DownEvent();
1955a4503c3SWaldemar Kornewald return true;
1964e0ad752SWaldemar Kornewald // there was no error
1975a4503c3SWaldemar Kornewald }
1985a4503c3SWaldemar Kornewald
1995a4503c3SWaldemar Kornewald fState = PADI_SENT;
2004e0ad752SWaldemar Kornewald // needed before sending, otherwise we might not get all packets
2014e0ad752SWaldemar Kornewald
202e3724c38Smshlyn status_t status = gStackModule->register_device_handler(fEthernetIfnet,
203e3724c38Smshlyn B_NET_FRAME_TYPE_PPPOE_DISCOVERY, &pppoe_input, NULL);
204e3724c38Smshlyn if (status != B_OK)
205e3724c38Smshlyn return false;
206e3724c38Smshlyn
207e3724c38Smshlyn status = gStackModule->register_device_handler(fEthernetIfnet,
208e3724c38Smshlyn B_NET_FRAME_TYPE_PPPOE, &pppoe_input, NULL);
209e3724c38Smshlyn if (status != B_OK)
210e3724c38Smshlyn return false;
211e3724c38Smshlyn
212e3724c38Smshlyn if (EthernetIfnet()->module->send_data(EthernetIfnet(), packet) != B_OK) {
2134e0ad752SWaldemar Kornewald fState = INITIAL;
2144e0ad752SWaldemar Kornewald fAttempts = 0;
21584b580c4SWaldemar Kornewald ERROR("PPPoEDevice::Up(): EthernetIfnet()->output() failed!\n");
2164e0ad752SWaldemar Kornewald return false;
2174e0ad752SWaldemar Kornewald }
2185a4503c3SWaldemar Kornewald
219e3724c38Smshlyn dprintf("PPPoEDevice::Up(): EthernetIfnet()->output() success!\n");
2205a4503c3SWaldemar Kornewald fNextTimeout = system_time() + PPPoE_TIMEOUT;
2215a4503c3SWaldemar Kornewald
2225a4503c3SWaldemar Kornewald return true;
2235a4503c3SWaldemar Kornewald }
2245a4503c3SWaldemar Kornewald
2255a4503c3SWaldemar Kornewald
2265a4503c3SWaldemar Kornewald bool
Down()2275a4503c3SWaldemar Kornewald PPPoEDevice::Down()
2285a4503c3SWaldemar Kornewald {
22984b580c4SWaldemar Kornewald TRACE("PPPoEDevice: Down()\n");
2305a4503c3SWaldemar Kornewald
231e3724c38Smshlyn gStackModule->unregister_device_handler(fEthernetIfnet,
232e3724c38Smshlyn B_NET_FRAME_TYPE_PPPOE_DISCOVERY);
233e3724c38Smshlyn gStackModule->unregister_device_handler(fEthernetIfnet,
234e3724c38Smshlyn B_NET_FRAME_TYPE_PPPOE);
235e3724c38Smshlyn
2362f13f213SWaldemar Kornewald remove_device(this);
2372f13f213SWaldemar Kornewald
2385a4503c3SWaldemar Kornewald if (InitCheck() != B_OK)
2395a4503c3SWaldemar Kornewald return false;
2405a4503c3SWaldemar Kornewald
2414e0ad752SWaldemar Kornewald fState = INITIAL;
2424e0ad752SWaldemar Kornewald fAttempts = 0;
2435a4503c3SWaldemar Kornewald fNextTimeout = 0;
2445a4503c3SWaldemar Kornewald // disable timeouts
2455a4503c3SWaldemar Kornewald
2465a4503c3SWaldemar Kornewald if (!IsUp()) {
2475a4503c3SWaldemar Kornewald DownEvent();
2485a4503c3SWaldemar Kornewald return true;
2495a4503c3SWaldemar Kornewald }
2505a4503c3SWaldemar Kornewald
2514e0ad752SWaldemar Kornewald // this tells StateMachine that DownEvent() does not mean we lost connection
252ceff2b88SAlexander von Gluck IV DownStarted();
2534e0ad752SWaldemar Kornewald
2545a4503c3SWaldemar Kornewald // create PADT
2555a4503c3SWaldemar Kornewald DiscoveryPacket discovery(PADT, SessionID());
2565a483e4dSWaldemar Kornewald discovery.AddTag(END_OF_LIST, NULL, 0);
2575a4503c3SWaldemar Kornewald
258e3724c38Smshlyn net_buffer *packet = discovery.ToNetBuffer(MTU());
2595a4503c3SWaldemar Kornewald if (!packet) {
260ceff2b88SAlexander von Gluck IV ERROR("PPPoEDevice::Down(): ToNetBuffer() failed; MTU=%" B_PRIu32 "\n",
261ceff2b88SAlexander von Gluck IV MTU());
2625a4503c3SWaldemar Kornewald DownEvent();
2635a4503c3SWaldemar Kornewald return false;
2645a4503c3SWaldemar Kornewald }
2655a4503c3SWaldemar Kornewald
2665a4503c3SWaldemar Kornewald // create destination
2674e0ad752SWaldemar Kornewald struct ether_header *ethernetHeader;
2685a4503c3SWaldemar Kornewald struct sockaddr destination;
2695a4503c3SWaldemar Kornewald memset(&destination, 0, sizeof(destination));
2705a4503c3SWaldemar Kornewald destination.sa_family = AF_UNSPEC;
2715a4503c3SWaldemar Kornewald // raw packet with ethernet header
2724e0ad752SWaldemar Kornewald ethernetHeader = (struct ether_header*) destination.sa_data;
273e3724c38Smshlyn ethernetHeader->type = ETHER_TYPE_PPPOE_DISCOVERY;
274e3724c38Smshlyn memcpy(ethernetHeader->destination, fPeer, sizeof(fPeer));
2755a4503c3SWaldemar Kornewald
2765a4503c3SWaldemar Kornewald // reset connection settings
2775a4503c3SWaldemar Kornewald memset(fPeer, 0xFF, sizeof(fPeer));
2785a4503c3SWaldemar Kornewald
279e3724c38Smshlyn EthernetIfnet()->module->send_data(EthernetIfnet(), packet);
2805a4503c3SWaldemar Kornewald DownEvent();
2815a4503c3SWaldemar Kornewald
2828dad9b1eSWaldemar Kornewald return true;
2835a4503c3SWaldemar Kornewald }
2845a4503c3SWaldemar Kornewald
2855a4503c3SWaldemar Kornewald
2865a4503c3SWaldemar Kornewald uint32
InputTransferRate() const2875a4503c3SWaldemar Kornewald PPPoEDevice::InputTransferRate() const
2885a4503c3SWaldemar Kornewald {
2895a4503c3SWaldemar Kornewald return 10000000;
2905a4503c3SWaldemar Kornewald }
2915a4503c3SWaldemar Kornewald
2925a4503c3SWaldemar Kornewald
2935a4503c3SWaldemar Kornewald uint32
OutputTransferRate() const2945a4503c3SWaldemar Kornewald PPPoEDevice::OutputTransferRate() const
2955a4503c3SWaldemar Kornewald {
2965a4503c3SWaldemar Kornewald return 10000000;
2975a4503c3SWaldemar Kornewald }
2985a4503c3SWaldemar Kornewald
2995a4503c3SWaldemar Kornewald
3005a4503c3SWaldemar Kornewald uint32
CountOutputBytes() const3015a4503c3SWaldemar Kornewald PPPoEDevice::CountOutputBytes() const
3025a4503c3SWaldemar Kornewald {
3035a4503c3SWaldemar Kornewald // TODO:
3045a4503c3SWaldemar Kornewald // ?look through ethernet queue for outgoing pppoe packets coming from our device?
3055a4503c3SWaldemar Kornewald return 0;
3065a4503c3SWaldemar Kornewald }
3075a4503c3SWaldemar Kornewald
3085a4503c3SWaldemar Kornewald
3095a4503c3SWaldemar Kornewald status_t
Send(net_buffer * packet,uint16 protocolNumber)310e3724c38Smshlyn PPPoEDevice::Send(net_buffer *packet, uint16 protocolNumber)
3115a4503c3SWaldemar Kornewald {
31286c13ddaSWaldemar Kornewald // Send() is only for PPP packets. PPPoE packets are sent directly to ethernet.
31386c13ddaSWaldemar Kornewald
31484b580c4SWaldemar Kornewald TRACE("PPPoEDevice: Send()\n");
3155a4503c3SWaldemar Kornewald
3168dad9b1eSWaldemar Kornewald if (!packet)
3178dad9b1eSWaldemar Kornewald return B_ERROR;
3188dad9b1eSWaldemar Kornewald else if (InitCheck() != B_OK || protocolNumber != 0) {
31984b580c4SWaldemar Kornewald ERROR("PPPoEDevice::Send(): InitCheck() != B_OK!\n");
320e3724c38Smshlyn gBufferModule->free(packet);
3215a4503c3SWaldemar Kornewald return B_ERROR;
3228dad9b1eSWaldemar Kornewald }
3235a4503c3SWaldemar Kornewald
3248dad9b1eSWaldemar Kornewald if (!IsUp()) {
32584b580c4SWaldemar Kornewald ERROR("PPPoEDevice::Send(): no connection!\n");
326e3724c38Smshlyn gBufferModule->free(packet);
3275a4503c3SWaldemar Kornewald return PPP_NO_CONNECTION;
3288dad9b1eSWaldemar Kornewald }
3295a4503c3SWaldemar Kornewald
330e3724c38Smshlyn uint16 length = packet->size;
3315a4503c3SWaldemar Kornewald
3325a4503c3SWaldemar Kornewald // encapsulate packet into pppoe header
333e3724c38Smshlyn NetBufferPrepend<pppoe_header> bufferheader(packet);
334e3724c38Smshlyn if (bufferheader.Status() != B_OK)
335e3724c38Smshlyn return B_ERROR;
336e3724c38Smshlyn pppoe_header &header = bufferheader.Data();
337e3724c38Smshlyn header.version = PPPoE_VERSION;
338e3724c38Smshlyn header.type = PPPoE_TYPE;
339e3724c38Smshlyn header.code = 0x00;
340e3724c38Smshlyn header.sessionID = SessionID();
341e3724c38Smshlyn header.length = htons(length);
342e3724c38Smshlyn bufferheader.Sync();
3435a4503c3SWaldemar Kornewald
344e3724c38Smshlyn // create ether header
345e3724c38Smshlyn NetBufferPrepend<ether_header> ethernetHeader(packet);
346e3724c38Smshlyn if (ethernetHeader.Status() != B_OK)
347e3724c38Smshlyn return false;
348e3724c38Smshlyn ether_header ðheader = ethernetHeader.Data();
349e3724c38Smshlyn
350e3724c38Smshlyn memcpy(ethheader.destination, fPeer, ETHER_ADDRESS_LENGTH);
351e3724c38Smshlyn memcpy(ethheader.source, fEtherAddr, ETHER_ADDRESS_LENGTH);
352e3724c38Smshlyn ethheader.type = htons(ETHER_TYPE_PPPOE);
353e3724c38Smshlyn ethernetHeader.Sync();
3545a4503c3SWaldemar Kornewald // raw packet with ethernet header
3555a4503c3SWaldemar Kornewald
356e3724c38Smshlyn if (!packet)
35784b580c4SWaldemar Kornewald ERROR("PPPoEDevice::Send(): packet is NULL!\n");
358abf44d1aSWaldemar Kornewald
359e3724c38Smshlyn if (EthernetIfnet()->module->send_data(EthernetIfnet(), packet) != B_OK) {
36084b580c4SWaldemar Kornewald ERROR("PPPoEDevice::Send(): EthernetIfnet()->output() failed!\n");
3612f13f213SWaldemar Kornewald remove_device(this);
3625a4503c3SWaldemar Kornewald DownEvent();
3635a4503c3SWaldemar Kornewald // DownEvent() without DownStarted() indicates connection lost
3645a4503c3SWaldemar Kornewald return PPP_NO_CONNECTION;
3655a4503c3SWaldemar Kornewald }
3665a4503c3SWaldemar Kornewald
3675a4503c3SWaldemar Kornewald return B_OK;
3685a4503c3SWaldemar Kornewald }
3695a4503c3SWaldemar Kornewald
3705a4503c3SWaldemar Kornewald
3715a4503c3SWaldemar Kornewald status_t
Receive(net_buffer * packet,uint16 protocolNumber)372e3724c38Smshlyn PPPoEDevice::Receive(net_buffer *packet, uint16 protocolNumber)
3735a4503c3SWaldemar Kornewald {
374e3724c38Smshlyn TRACE("%s entering %s: protocolNumber:%x\n", __FILE__, __func__, protocolNumber);
3758dad9b1eSWaldemar Kornewald if (!packet)
3768dad9b1eSWaldemar Kornewald return B_ERROR;
3775a4503c3SWaldemar Kornewald
378e3724c38Smshlyn if (InitCheck() != B_OK || IsDown()) {
379e3724c38Smshlyn dprintf("PPPoED InitCheck fail or IsDown\n");
380e3724c38Smshlyn // gBufferModule->free(packet);
381e3724c38Smshlyn dprintf("PPPoEDevice::Receive fail\n");
3825a4503c3SWaldemar Kornewald return B_ERROR;
3835a4503c3SWaldemar Kornewald }
3845a4503c3SWaldemar Kornewald
3854e0ad752SWaldemar Kornewald uint8 ethernetSource[6];
386e3724c38Smshlyn struct sockaddr_dl& source = *(struct sockaddr_dl*)packet->source;
387e3724c38Smshlyn memcpy(ethernetSource, source.sdl_data, sizeof(fPeer));
3885a4503c3SWaldemar Kornewald
389e3724c38Smshlyn int32 PPP_Packet_Type = B_NET_FRAME_TYPE(source.sdl_type,
390e3724c38Smshlyn ntohs(source.sdl_e_type));
391e3724c38Smshlyn // bufferheader.Remove();
392e3724c38Smshlyn // bufferheader.Sync();
3934e0ad752SWaldemar Kornewald
394e3724c38Smshlyn if (PPP_Packet_Type == B_NET_FRAME_TYPE_PPPOE) {
395e3724c38Smshlyn TRACE("ETHER_TYPE_PPPOE\n");
396e3724c38Smshlyn NetBufferHeaderReader<pppoe_header> bufferheader(packet);
397e3724c38Smshlyn if (bufferheader.Status() != B_OK) {
398e3724c38Smshlyn TRACE("creat NetBufferHeaderReader fail\n");
399e3724c38Smshlyn return B_ERROR;
400e3724c38Smshlyn }
401e3724c38Smshlyn pppoe_header &header = bufferheader.Data();
402e3724c38Smshlyn uint16 ppppoe_payload = ntohs(header.length);
403e3724c38Smshlyn
404e3724c38Smshlyn if (!IsUp() || header.version != PPPoE_VERSION || header.type != PPPoE_TYPE
405e3724c38Smshlyn || header.code != 0x0 || header.sessionID != SessionID()) {
406e3724c38Smshlyn // gBufferModule->free(packet);
407e3724c38Smshlyn TRACE("basic pppoe header check fail\n");
4085a4503c3SWaldemar Kornewald return B_ERROR;
4095a4503c3SWaldemar Kornewald }
4105a4503c3SWaldemar Kornewald
411e3724c38Smshlyn bufferheader.Remove();
412e3724c38Smshlyn bufferheader.Sync();
413e3724c38Smshlyn
414e3724c38Smshlyn // trim the packet according to actual pppoe_payload
415e3724c38Smshlyn gBufferModule->trim(packet, ppppoe_payload);
416e3724c38Smshlyn
4175a4503c3SWaldemar Kornewald return Interface().ReceiveFromDevice(packet);
418e3724c38Smshlyn }
419e3724c38Smshlyn
420e3724c38Smshlyn if (PPP_Packet_Type == B_NET_FRAME_TYPE_PPPOE_DISCOVERY) {
421e3724c38Smshlyn dprintf("ETHER_TYPE_PPPOE_DISCOVERY\n");
422e3724c38Smshlyn NetBufferHeaderReader<pppoe_header> bufferheader(packet);
423e3724c38Smshlyn if (bufferheader.Status() != B_OK) {
424e3724c38Smshlyn dprintf("create NetBufferHeaderReader fail\n");
425e3724c38Smshlyn return B_ERROR;
426e3724c38Smshlyn }
427e3724c38Smshlyn pppoe_header &header = bufferheader.Data();
4284e0ad752SWaldemar Kornewald
4295a4503c3SWaldemar Kornewald // we do not need to check HOST_UNIQ tag as this is done in pppoe.cpp
430e3724c38Smshlyn if (header.version != PPPoE_VERSION || header.type != PPPoE_TYPE) {
431e3724c38Smshlyn // gBufferModule->free(packet);
432e3724c38Smshlyn dprintf("PPPoEDevice::Receive fail version type wrong\n");
4335a4503c3SWaldemar Kornewald return B_ERROR;
4345a4503c3SWaldemar Kornewald }
4355a4503c3SWaldemar Kornewald
4365a4503c3SWaldemar Kornewald if (IsDown()) {
437e3724c38Smshlyn // gBufferModule->free(packet);
438e3724c38Smshlyn dprintf("PPPoEDevice::Receive fail PPPoEDev IsDown\n");
4395a4503c3SWaldemar Kornewald return B_ERROR;
4405a4503c3SWaldemar Kornewald }
4415a4503c3SWaldemar Kornewald
4425a4503c3SWaldemar Kornewald DiscoveryPacket discovery(packet);
4435a4503c3SWaldemar Kornewald switch(discovery.Code()) {
4445a4503c3SWaldemar Kornewald case PADO: {
445e3724c38Smshlyn dprintf("processing PADO\n");
4465a4503c3SWaldemar Kornewald if (fState != PADI_SENT) {
447e3724c38Smshlyn // gBufferModule->free(packet);
448e3724c38Smshlyn dprintf("PPPoEDevice::Receive faile not PADI_Sent \n");
4495a4503c3SWaldemar Kornewald return B_OK;
4505a4503c3SWaldemar Kornewald }
4515a4503c3SWaldemar Kornewald
4525a483e4dSWaldemar Kornewald bool hasServiceName = false, hasACName = false;
4535a4503c3SWaldemar Kornewald pppoe_tag *tag;
4545a4503c3SWaldemar Kornewald DiscoveryPacket reply(PADR);
4555a4503c3SWaldemar Kornewald for (int32 index = 0; index < discovery.CountTags(); index++) {
4565a4503c3SWaldemar Kornewald tag = discovery.TagAt(index);
457abf44d1aSWaldemar Kornewald if (!tag)
458abf44d1aSWaldemar Kornewald continue;
459abf44d1aSWaldemar Kornewald
4605a4503c3SWaldemar Kornewald switch (tag->type) {
4615a4503c3SWaldemar Kornewald case SERVICE_NAME:
4625a483e4dSWaldemar Kornewald if (!hasServiceName && (!ServiceName()
463e3724c38Smshlyn || ((strlen(ServiceName()) == tag->length)
4645a483e4dSWaldemar Kornewald && !memcmp(tag->data, ServiceName(),
465e3724c38Smshlyn tag->length)))) {
4665a4503c3SWaldemar Kornewald hasServiceName = true;
4675a483e4dSWaldemar Kornewald reply.AddTag(tag->type, tag->data, tag->length);
4685a483e4dSWaldemar Kornewald }
4695a483e4dSWaldemar Kornewald break;
4705a483e4dSWaldemar Kornewald
4715a483e4dSWaldemar Kornewald case AC_NAME:
4725a483e4dSWaldemar Kornewald if (!hasACName && (!ACName()
473e3724c38Smshlyn || ((strlen(ACName()) == tag->length)
4745a483e4dSWaldemar Kornewald && !memcmp(tag->data, ACName(),
475e3724c38Smshlyn tag->length)))) {
4765a483e4dSWaldemar Kornewald hasACName = true;
4775a483e4dSWaldemar Kornewald reply.AddTag(tag->type, tag->data, tag->length);
4785a4503c3SWaldemar Kornewald }
4795a4503c3SWaldemar Kornewald break;
4805a4503c3SWaldemar Kornewald
4815a4503c3SWaldemar Kornewald case AC_COOKIE:
4825a4503c3SWaldemar Kornewald case RELAY_SESSION_ID:
4835a483e4dSWaldemar Kornewald reply.AddTag(tag->type, tag->data, tag->length);
4845a4503c3SWaldemar Kornewald break;
4855a4503c3SWaldemar Kornewald
4865a4503c3SWaldemar Kornewald case SERVICE_NAME_ERROR:
4875a4503c3SWaldemar Kornewald case AC_SYSTEM_ERROR:
4885a4503c3SWaldemar Kornewald case GENERIC_ERROR:
489e3724c38Smshlyn // gBufferModule->free(packet);
490e3724c38Smshlyn dprintf("PPPoEDevice::generic error faile\n");
4915a4503c3SWaldemar Kornewald return B_ERROR;
4925a4503c3SWaldemar Kornewald break;
4935a4503c3SWaldemar Kornewald
4945a4503c3SWaldemar Kornewald default:
4955a4503c3SWaldemar Kornewald ;
4965a4503c3SWaldemar Kornewald }
4975a4503c3SWaldemar Kornewald }
4985a4503c3SWaldemar Kornewald
4995a4503c3SWaldemar Kornewald if (!hasServiceName) {
500e3724c38Smshlyn // gBufferModule->free(packet);
501e3724c38Smshlyn dprintf("PPPoEDevice::Receive faile no svc name\n");
5025a4503c3SWaldemar Kornewald return B_ERROR;
5035a4503c3SWaldemar Kornewald }
5045a4503c3SWaldemar Kornewald
505e3724c38Smshlyn dprintf("reply.AddTag\n");
5065a483e4dSWaldemar Kornewald reply.AddTag(HOST_UNIQ, &fHostUniq, sizeof(fHostUniq));
5075a483e4dSWaldemar Kornewald reply.AddTag(END_OF_LIST, NULL, 0);
508e3724c38Smshlyn net_buffer *replyPacket = reply.ToNetBuffer(MTU());
5095a4503c3SWaldemar Kornewald if (!replyPacket) {
510e3724c38Smshlyn // gBufferModule->free(packet);
511e3724c38Smshlyn dprintf("PPPoEDevice::Receive fail no reply pack\n");
5125a4503c3SWaldemar Kornewald return B_ERROR;
5135a4503c3SWaldemar Kornewald }
5145a4503c3SWaldemar Kornewald
515e3724c38Smshlyn memcpy(fPeer, ethernetSource, ETHER_ADDRESS_LENGTH);
5165a4503c3SWaldemar Kornewald
517e3724c38Smshlyn // create ether header
518e3724c38Smshlyn NetBufferPrepend<ether_header> ethernetHeader(replyPacket);
519e3724c38Smshlyn if (ethernetHeader.Status() != B_OK)
520e3724c38Smshlyn return false;
521e3724c38Smshlyn ether_header &header = ethernetHeader.Data();
522e3724c38Smshlyn
523e3724c38Smshlyn memcpy(header.destination, fPeer, ETHER_ADDRESS_LENGTH);
524e3724c38Smshlyn memcpy(header.source, fEtherAddr, ETHER_ADDRESS_LENGTH);
525e3724c38Smshlyn header.type=htons(ETHER_TYPE_PPPOE_DISCOVERY);
526e3724c38Smshlyn ethernetHeader.Sync();
5275a4503c3SWaldemar Kornewald // raw packet with ethernet header
5284e0ad752SWaldemar Kornewald
5294e0ad752SWaldemar Kornewald fState = PADR_SENT;
5305a4503c3SWaldemar Kornewald
531e3724c38Smshlyn if (EthernetIfnet()->module->send_data(EthernetIfnet(), replyPacket) != B_OK) {
532e3724c38Smshlyn gBufferModule->free(replyPacket);
533e3724c38Smshlyn dprintf("PPPoEDevice::Receive fail send PADR\n");
5345a4503c3SWaldemar Kornewald return B_ERROR;
5355a4503c3SWaldemar Kornewald }
5365a4503c3SWaldemar Kornewald
5375a4503c3SWaldemar Kornewald fNextTimeout = system_time() + PPPoE_TIMEOUT;
538e3724c38Smshlyn }
539e3724c38Smshlyn break;
5405a4503c3SWaldemar Kornewald case PADS:
541e3724c38Smshlyn dprintf("procesing PADS\n");
5425a4503c3SWaldemar Kornewald if (fState != PADR_SENT
5434e0ad752SWaldemar Kornewald || memcmp(ethernetSource, fPeer, sizeof(fPeer))) {
544e3724c38Smshlyn // gBufferModule->free(packet);
545e3724c38Smshlyn dprintf("PPPoEDevice::Receive PADS but no PADR sent\n");
5465a4503c3SWaldemar Kornewald return B_ERROR;
5475a4503c3SWaldemar Kornewald }
5485a4503c3SWaldemar Kornewald
549e3724c38Smshlyn fSessionID = header.sessionID;
5505a4503c3SWaldemar Kornewald fState = OPENED;
5515a4503c3SWaldemar Kornewald fNextTimeout = 0;
5525a4503c3SWaldemar Kornewald UpEvent();
5535a4503c3SWaldemar Kornewald break;
5545a4503c3SWaldemar Kornewald
5555a4503c3SWaldemar Kornewald case PADT:
556e3724c38Smshlyn dprintf("procesing PADT\n");
5575a4503c3SWaldemar Kornewald if (!IsUp()
5584e0ad752SWaldemar Kornewald || memcmp(ethernetSource, fPeer, sizeof(fPeer))
559e3724c38Smshlyn || header.sessionID != SessionID()) {
560e3724c38Smshlyn // gBufferModule->free(packet);
561e3724c38Smshlyn dprintf("PPPoEDevice::Receive fail not up yet\n");
5625a4503c3SWaldemar Kornewald return B_ERROR;
5635a4503c3SWaldemar Kornewald }
5645a4503c3SWaldemar Kornewald
5655a4503c3SWaldemar Kornewald fState = INITIAL;
5664e0ad752SWaldemar Kornewald fAttempts = 0;
5675a4503c3SWaldemar Kornewald fSessionID = 0;
5685a4503c3SWaldemar Kornewald fNextTimeout = 0;
5692f13f213SWaldemar Kornewald remove_device(this);
5705a4503c3SWaldemar Kornewald DownEvent();
5715a4503c3SWaldemar Kornewald break;
5725a4503c3SWaldemar Kornewald
5735a4503c3SWaldemar Kornewald default:
574e3724c38Smshlyn dprintf("PPPoEDevice::Receive fail unknown pppoed code\n");
575e3724c38Smshlyn // gBufferModule->free(packet);
5765a4503c3SWaldemar Kornewald return B_ERROR;
5775a4503c3SWaldemar Kornewald }
578e3724c38Smshlyn }
5795a4503c3SWaldemar Kornewald
580e3724c38Smshlyn dprintf("PPPoEDevice::Receive PADX fine!\n");
581e3724c38Smshlyn // gBufferModule->free(packet);
582e3724c38Smshlyn return B_OK;
5835a4503c3SWaldemar Kornewald }
5845a4503c3SWaldemar Kornewald
5855a4503c3SWaldemar Kornewald
5865a4503c3SWaldemar Kornewald void
Pulse()5875a4503c3SWaldemar Kornewald PPPoEDevice::Pulse()
5885a4503c3SWaldemar Kornewald {
5895a4503c3SWaldemar Kornewald // We use Pulse() for timeout of connection establishment.
5905a4503c3SWaldemar Kornewald if (fNextTimeout == 0 || IsUp() || IsDown())
5915a4503c3SWaldemar Kornewald return;
5925a4503c3SWaldemar Kornewald
5935a4503c3SWaldemar Kornewald // check if timed out
5944e0ad752SWaldemar Kornewald if (system_time() >= fNextTimeout) {
5954e0ad752SWaldemar Kornewald if (!Up())
5964e0ad752SWaldemar Kornewald UpFailedEvent();
5974e0ad752SWaldemar Kornewald }
5985a4503c3SWaldemar Kornewald }
599