xref: /haiku/src/add-ons/kernel/network/ppp/pppoe/PPPoEDevice.cpp (revision 5d1791071ef0bc8149ccde69a92ec080e6d38788)
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 &ethheader = 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