1/*
2 * Copyright 2003-2006, Waldemar Kornewald <wkornew@gmx.net>
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <KernelExport.h>
7#include <driver_settings.h>
8
9#include <lock.h>
10#include <util/AutoLock.h>
11#include <ByteOrder.h>
12
13#include <net/if_types.h>
14#include <net/if_dl.h>
15#include <net/if.h>
16#include <sys/sockio.h>
17
18#include <net_buffer.h>
19#include <net_datalink.h> // for get_interface and control
20#include <net_stack.h>
21#include <NetBufferUtilities.h>
22
23#include <KPPPInterface.h>
24#include <KPPPModule.h>
25#include <KPPPUtils.h>
26
27#include "PPPoEDevice.h"
28#include "DiscoveryPacket.h"
29
30
31typedef struct pppoe_query {
32	net_device *ethernetIfnet;
33	uint32 hostUniq;
34	thread_id receiver;
35} pppoe_query;
36
37#define PPPoE_MODULE_NAME	"network/ppp/pppoe"
38
39net_stack_module_info *gStackModule = NULL;
40net_buffer_module_info *gBufferModule = NULL;
41net_datalink_module_info *sDatalinkModule = NULL;
42
43static int32 sHostUniq = 0;
44status_t std_ops(int32 op, ...);
45
46// static mutex sLock("PPPoEList");
47
48static TemplateList<PPPoEDevice*> *sDevices;
49static TemplateList<pppoe_query*> *sQueries;
50
51
52static
53void
54SendQueryPacket(pppoe_query *query, DiscoveryPacket& discovery)
55{
56	char data[PPPoE_QUERY_REPORT_SIZE];
57	uint32 position = sizeof(uint32);
58	pppoe_tag *acName = discovery.TagWithType(AC_NAME);
59
60	if (acName) {
61		if (acName->length >= PPPoE_QUERY_REPORT_SIZE)
62			return;
63
64		memcpy(data + position, acName->data, acName->length);
65		position += acName->length;
66	}
67
68	data[position++] = 0;
69
70	pppoe_tag *tag;
71	for (int32 index = 0; index < discovery.CountTags(); index++) {
72		tag = discovery.TagAt(index);
73		if (tag && tag->type == SERVICE_NAME) {
74			if (position + tag->length >= PPPoE_QUERY_REPORT_SIZE)
75				return;
76
77			memcpy(data + position, tag->data, tag->length);
78			position += tag->length;
79			data[position++] = 0;
80		}
81	}
82
83	memcpy(data, &position, sizeof(uint32));
84		// add the total length
85
86	send_data_with_timeout(query->receiver, PPPoE_QUERY_REPORT, data,
87		PPPoE_QUERY_REPORT_SIZE, 700000);
88}
89
90
91net_interface *
92get_interface_by_name(net_domain *domain, const char *name)
93{
94	ifreq request;
95	memset(&request, 0, sizeof(request));
96	size_t size = sizeof(request);
97
98	strlcpy(request.ifr_name, name, IF_NAMESIZE);
99
100	if (sDatalinkModule->control(domain, SIOCGIFINDEX, &request, &size) != B_OK) {
101		TRACE("sDatalinkModule->control failure\n");
102		return NULL;
103	}
104	return sDatalinkModule->get_interface(domain, request.ifr_index);
105}
106
107
108net_device*
109FindPPPoEInterface(const char *name)
110{
111	if (!name)
112		return NULL;
113
114	net_interface* ethernetInterfaceOfPPPOE = NULL;
115	net_domain* domain = NULL;
116
117	domain = gStackModule->get_domain(AF_INET);
118	ethernetInterfaceOfPPPOE = get_interface_by_name(domain, name);
119
120	if (ethernetInterfaceOfPPPOE == NULL) {
121		TRACE("get_interface_by_name can not find eth\n");
122		return NULL;
123	}
124
125	if (ethernetInterfaceOfPPPOE->device)
126		return ethernetInterfaceOfPPPOE->device;
127
128	return NULL;
129}
130
131
132uint32
133NewHostUniq()
134{
135	return (uint32) atomic_add(&sHostUniq, 1);
136}
137
138
139void
140add_device(PPPoEDevice *device)
141{
142	TRACE("PPPoE: add_device()\n");
143
144	// MutexLocker locker(sLock);
145	if (!sDevices->HasItem(device))
146		sDevices->AddItem(device);
147}
148
149
150void
151remove_device(PPPoEDevice *device)
152{
153	TRACE("PPPoE: remove_device()\n");
154
155	// MutexLocker locker(sLock);
156	sDevices->RemoveItem(device);
157}
158
159
160status_t
161pppoe_input(void *cookie, net_device *_device, net_buffer *packet)
162{
163	if (!packet)
164		return B_ERROR;
165
166	NetBufferHeaderReader<pppoe_header> bufferheader(packet);
167	if (bufferheader.Status() != B_OK)
168		return B_ERROR;
169
170	pppoe_header &header = bufferheader.Data();
171
172	// remove the following lines when pppoe server is enabled
173	if (header.code == PADI) {
174		TRACE("PADI packet received, ignoreing!\n");
175		gBufferModule->free(packet);
176		return B_OK;
177	}
178
179	if (header.code == PADO || header.code == PADR || header.code == PADS || header.code == PADT)
180	{
181		uint8 peerEtherAddr[ETHER_ADDRESS_LENGTH];
182		struct sockaddr_dl& source = *(struct sockaddr_dl*)packet->source;
183		memcpy(peerEtherAddr, source.sdl_data, ETHER_ADDRESS_LENGTH);
184		const char *str = header.code == PADI ? "PADI" :
185			header.code == PADO ? "PADO" :
186			header.code == PADR ? "PADR" :
187			header.code == PADS ? "PADS" :
188			"PADT" ;
189
190		dprintf("%s from:%02x:%02x:%02x:%02x:%02x:%02x code:%02x\n", str,
191			peerEtherAddr[0], peerEtherAddr[1], peerEtherAddr[2],
192			peerEtherAddr[3], peerEtherAddr[4], peerEtherAddr[5],
193			header.code);
194	}
195
196	PPPoEDevice *device;
197	pppoe_query *query;
198
199	sockaddr_dl& linkAddress = *(sockaddr_dl*)packet->source;
200	int32 specificType = B_NET_FRAME_TYPE(linkAddress.sdl_type,
201				ntohs(linkAddress.sdl_e_type));
202
203	// MutexLocker locker(sLock);
204
205	if (specificType == B_NET_FRAME_TYPE_PPPOE_DISCOVERY
206			&& ntohs(header.length) <= PPPoE_QUERY_REPORT_SIZE) {
207		for (int32 index = 0; index < sDevices->CountItems(); index++) {
208			query = sQueries->ItemAt(index);
209
210			if (query) {// && query->ethernetIfnet == sourceIfnet) {
211				if (header.code == PADO) {
212					DiscoveryPacket discovery(packet, ETHER_HDR_LEN);
213					if (discovery.InitCheck() != B_OK) {
214						ERROR("PPPoE: received corrupted discovery packet!\n");
215						// gBufferModule->free(packet);
216						return B_ERROR;
217					}
218
219					pppoe_tag *hostTag = discovery.TagWithType(HOST_UNIQ);
220					if (hostTag && hostTag->length == 4
221							&& *((uint32*)hostTag->data) == query->hostUniq) {
222						SendQueryPacket(query, discovery);
223						// gBufferModule->free(packet);
224						return B_ERROR;
225					}
226				}
227			}
228		}
229	}
230
231	TRACE("in pppoed processing sDevices->CountItems(): %" B_PRId32 "\n",
232		sDevices->CountItems());
233
234	for (int32 index = 0; index < sDevices->CountItems(); index++) {
235		device = sDevices->ItemAt(index);
236
237		TRACE("device->SessionID() %d, header.sessionID: %d\n", device->SessionID(),
238						header.sessionID);
239
240		if (device) { // && device->EthernetIfnet() == sourceIfnet) {
241			if (specificType == B_NET_FRAME_TYPE_PPPOE
242					&& header.sessionID == device->SessionID()) {
243				TRACE("PPPoE: session packet\n");
244				device->Receive(packet);
245				return B_OK;
246			}
247
248			if (specificType == B_NET_FRAME_TYPE_PPPOE_DISCOVERY
249					&& header.code != PADI
250					&& header.code != PADR
251					&& !device->IsDown()) {
252				TRACE("PPPoE: discovery packet\n");
253
254				DiscoveryPacket discovery(packet, ETHER_HDR_LEN);
255				if (discovery.InitCheck() != B_OK) {
256					ERROR("PPPoE: received corrupted discovery packet!\n");
257					gBufferModule->free(packet);
258					return B_OK;
259				}
260
261				pppoe_tag *tag = discovery.TagWithType(HOST_UNIQ);
262				if (header.code == PADT || (tag && tag->length == 4
263					&& *((uint32*)tag->data) == device->HostUniq())) {
264					device->Receive(packet);
265					return B_OK;
266				}
267			}
268		}
269	}
270
271	ERROR("PPPoE: No device found for packet from: %s\n", "ethernet");
272	// gBufferModule->free(packet);
273	return B_ERROR;
274}
275
276
277static
278bool
279add_to(KPPPInterface& mainInterface, KPPPInterface *subInterface,
280	driver_parameter *settings, ppp_module_key_type type)
281{
282	if (mainInterface.Mode() != PPP_CLIENT_MODE || type != PPP_DEVICE_KEY_TYPE)
283		return B_ERROR;
284
285	PPPoEDevice *device;
286	bool success;
287	if (subInterface) {
288		device = new PPPoEDevice(*subInterface, settings);
289		success = subInterface->SetDevice(device);
290	} else {
291		device = new PPPoEDevice(mainInterface, settings);
292		success = mainInterface.SetDevice(device);
293	}
294
295	TRACE("PPPoE: add_to(): %s\n",
296		success && device && device->InitCheck() == B_OK ? "OK" : "ERROR");
297
298	return success && device && device->InitCheck() == B_OK;
299}
300
301
302static
303status_t
304control(uint32 op, void *data, size_t length)
305{
306	switch (op) {
307		case PPPoE_GET_INTERFACES: {
308			int32 position = 0, count = 0;
309			char *names = (char*) data;
310
311			net_device *current = NULL; // get_interfaces();
312			for (; current; current = NULL) {
313				if (current->type == IFT_ETHER && current->name) {
314					if (position + strlen(current->name) + 1 > length)
315						return B_NO_MEMORY;
316
317					strcpy(names + position, current->name);
318					position += strlen(current->name);
319					names[position++] = 0;
320					++count;
321				}
322			}
323
324			return count;
325		}
326
327		case PPPoE_QUERY_SERVICES: {
328			// XXX: as all modules are loaded on-demand we must wait for the results
329
330			if (!data || length != sizeof(pppoe_query_request))
331				return B_ERROR;
332
333			pppoe_query_request *request = (pppoe_query_request*) data;
334
335			pppoe_query query;
336			query.ethernetIfnet = FindPPPoEInterface(request->interfaceName);
337			if (!query.ethernetIfnet)
338				return B_BAD_VALUE;
339
340			query.hostUniq = NewHostUniq();
341			query.receiver = request->receiver;
342
343			{
344				// MutexLocker tlocker(sLock);
345				TRACE("add query\n");
346				sQueries->AddItem(&query);
347			}
348
349			snooze(2000000);
350				// wait two seconds for results
351			{
352				// MutexLocker tlocker(sLock);
353				TRACE("remove query\n");
354				sQueries->RemoveItem(&query);
355			}
356		} break;
357
358		default:
359			return B_ERROR;
360	}
361
362	return B_OK;
363}
364
365
366static ppp_module_info pppoe_module = {
367	{
368		PPPoE_MODULE_NAME,
369		0,
370		std_ops
371	},
372	control,
373	add_to
374};
375
376
377_EXPORT
378status_t
379std_ops(int32 op, ...)
380{
381	switch(op) {
382		case B_MODULE_INIT:
383			if (get_module(NET_STACK_MODULE_NAME,
384				(module_info**)&gStackModule) != B_OK)
385				return B_ERROR;
386
387			if (get_module(NET_DATALINK_MODULE_NAME,
388				(module_info **)&sDatalinkModule) != B_OK) {
389				put_module(NET_STACK_MODULE_NAME);
390				return B_ERROR;
391			}
392
393			if (get_module(NET_BUFFER_MODULE_NAME,
394				(module_info **)&gBufferModule) != B_OK) {
395				put_module(NET_DATALINK_MODULE_NAME);
396				put_module(NET_STACK_MODULE_NAME);
397				return B_ERROR;
398			}
399
400			// set_max_linkhdr(2 + PPPoE_HEADER_SIZE + ETHER_HDR_LEN);
401				// 2 bytes for PPP header
402			sDevices = new TemplateList<PPPoEDevice*>;
403			sQueries = new TemplateList<pppoe_query*>;
404
405			TRACE("PPPoE: Registered PPPoE receiver.\n");
406			return B_OK;
407
408		case B_MODULE_UNINIT:
409			delete sQueries;
410			delete sDevices;
411			TRACE("PPPoE: Unregistered PPPoE receiver.\n");
412			put_module(NET_BUFFER_MODULE_NAME);
413			put_module(NET_DATALINK_MODULE_NAME);
414			put_module(NET_STACK_MODULE_NAME);
415			break;
416
417		default:
418			return B_ERROR;
419	}
420
421	return B_OK;
422}
423
424
425_EXPORT
426module_info *modules[] = {
427	(module_info*) &pppoe_module,
428	NULL
429};
430