xref: /haiku/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 
31 typedef 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 
39 net_stack_module_info *gStackModule = NULL;
40 net_buffer_module_info *gBufferModule = NULL;
41 net_datalink_module_info *sDatalinkModule = NULL;
42 
43 static int32 sHostUniq = 0;
44 status_t std_ops(int32 op, ...);
45 
46 // static mutex sLock("PPPoEList");
47 
48 static TemplateList<PPPoEDevice*> *sDevices;
49 static TemplateList<pppoe_query*> *sQueries;
50 
51 
52 static
53 void
54 SendQueryPacket(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 
91 net_interface *
92 get_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 
108 net_device*
109 FindPPPoEInterface(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 
132 uint32
133 NewHostUniq()
134 {
135 	return (uint32) atomic_add(&sHostUniq, 1);
136 }
137 
138 
139 void
140 add_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 
150 void
151 remove_device(PPPoEDevice *device)
152 {
153 	TRACE("PPPoE: remove_device()\n");
154 
155 	// MutexLocker locker(sLock);
156 	sDevices->RemoveItem(device);
157 }
158 
159 
160 status_t
161 pppoe_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 
277 static
278 bool
279 add_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 
302 static
303 status_t
304 control(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 
366 static 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
378 status_t
379 std_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
426 module_info *modules[] = {
427 	(module_info*) &pppoe_module,
428 	NULL
429 };
430