1/*
2 * Copyright 2014, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Lin Longzhou, linlongzhou@163.com
7 */
8
9
10#include <errno.h>
11#include <stdlib.h>
12#include <net/if_dl.h>
13#include <net/if_media.h>
14#include <net/if_types.h>
15#include <new>
16
17#include <ethernet.h>
18#include <ether_driver.h>
19#include <net_buffer.h>
20#include <net_datalink_protocol.h>
21
22#include <NetBufferUtilities.h>
23#include <net_stack.h>
24
25#include <KernelExport.h>
26
27#include <KPPPManager.h>
28#include <ppp_device.h>
29
30#define PPP_HEADER_LENGTH (8 + ETHER_HEADER_LENGTH)
31
32
33net_buffer* create_buffer_for_frame(uint8 *frame, uint16 frame_size);
34
35static const bigtime_t kLinkCheckInterval = 1000000;
36	// 1 second
37
38net_buffer_module_info *gBufferModule;
39ppp_interface_module_info* gPPPInterfaceModule;
40static net_stack_module_info *sStackModule;
41
42static mutex sListLock;
43static DoublyLinkedList<ppp_device> sCheckList;
44static sem_id sLinkChangeSemaphore;
45static thread_id sLinkCheckerThread;
46
47
48//	#pragma mark -
49//
50
51status_t
52ppp_init(const char *name, net_device **_device)
53{
54	// ppp device
55	dprintf("%s: entering!\n", __func__);
56
57	if (strncmp(name, "ppp", 3)) {
58		dprintf("[%s] not ppp device\n", name);
59		return B_BAD_VALUE;
60	}
61
62	dprintf("[%s] is ppp device\n", name);
63
64	status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
65	if (status < B_OK)
66		return status;
67
68	// ppp_device *device = new (std::nothrow) ppp_device;
69	ppp_interface_id idInterface = gPPPInterfaceModule->CreateInterfaceWithName(name, 0);
70	KPPPInterface * pppInterface = gPPPInterfaceModule->GetInterface(idInterface);
71
72	if (idInterface <= 0 || pppInterface == NULL) {
73		if (idInterface <= 0)
74			dprintf("%s: idInterface: %" B_PRIu32 "\n", __func__, idInterface);
75		else
76			dprintf("%s: pppInterface == NULL %" B_PRIu32 "\n", __func__, idInterface);
77		put_module(NET_BUFFER_MODULE_NAME);
78		return B_NO_MEMORY;
79	}
80
81	// Ifnet available until interface up phase
82	ppp_device *device = (ppp_device *)pppInterface->Ifnet();
83	if (device == NULL) {
84		dprintf("%s: can not get ppp_device\n", __func__);
85		put_module(NET_BUFFER_MODULE_NAME);
86		return B_NO_MEMORY;
87	}
88
89	strcpy(device->name, name);
90	device->flags = (IFF_BROADCAST | IFF_LINK) & (~IFF_UP);
91	device->type = IFT_PPP;
92	device->mtu = 1492;
93	device->frame_size = 1500;
94	device->media = IFM_ACTIVE | IFM_ETHER;
95	device->header_length = PPP_HEADER_LENGTH;
96
97	status =sStackModule->init_fifo(&(device->ppp_fifo), "ppp_fifo", 10 * 1500);
98		// 10 ppp packet at most
99	if (status < B_OK)
100		return(status);
101
102	TRACE("[%s] finish\n", "allocate ppp_device");
103	*_device = device;
104
105	return B_OK;
106}
107
108
109status_t
110ppp_uninit(net_device *device)
111{
112	dprintf("%s:  uninit ppp\n", __func__);
113	ppp_device *ppp_dev=(ppp_device *)device;
114
115	sStackModule->uninit_fifo(&(ppp_dev->ppp_fifo));
116	put_module(NET_BUFFER_MODULE_NAME);
117
118	// delete ppp_dev->KPPP_Interface;
119	delete ppp_dev;
120
121	return B_OK;
122}
123
124
125status_t
126ppp_up(net_device *_device)
127{
128	dprintf("ppp_up\n");
129	ppp_device *device = (ppp_device *)_device;
130
131	if (device->KPPP_Interface == NULL) {
132		dprintf("%s: warning! can not find pppinterface KPPP_Interface\n", __func__);
133		return B_ERROR;
134	}
135
136	if (device->KPPP_Interface->Up() != true) {
137		dprintf("%s: warning! KPPP_Interface->Up() failure\n", __func__);
138		return B_ERROR;
139	}
140
141	device->mtu = device->frame_size - device->header_length;
142	// s_pppoe_dev = device;
143
144	dprintf("%s: congratulations! Find pppinterface (device->KPPP_Interface)\n", __func__);
145
146	return B_OK;
147}
148
149
150void
151ppp_down(net_device *_device)
152{
153	dprintf("%s\n", __func__);
154	ppp_device *device = (ppp_device *)_device;
155	device->KPPP_Interface->Down();
156
157	MutexLocker _(sListLock);
158
159	// if the device is still part of the list, remove it
160	if (device->GetDoublyLinkedListLink()->next != NULL
161		|| device->GetDoublyLinkedListLink()->previous != NULL
162		|| device == sCheckList.Head())
163		sCheckList.Remove(device);
164
165	// device->KPPP_Interface = NULL;
166
167	return;
168}
169
170
171status_t
172ppp_control(net_device *_device, int32 op, void *argument,
173	size_t length)
174{
175	TRACE("%s op:%" B_PRId32 "\n", __func__, op);
176	ppp_device *device = (ppp_device *)_device;
177
178	if (device->KPPP_Interface == NULL) {
179		dprintf("%s: can not find KPPP_Interface for ppp\n", __func__);
180		return B_OK;
181	}
182
183	return device->KPPP_Interface->Control(op, argument, length);
184
185	return B_OK;
186}
187
188
189status_t
190ppp_send_data(net_device *_device, net_buffer *buffer)
191{
192	TRACE("%s\n", __func__);
193	ppp_device *device = (ppp_device *)_device;
194
195	if (buffer->size > device->frame_size || buffer->size < device->header_length) {
196		dprintf("sorry! fail send ppp packet, size wrong!\n");
197		return EMSGSIZE;
198	}
199
200	if (device->KPPP_Interface == NULL) {
201		dprintf("Fail send ppp packet, no eth for ppp!\n");
202		return B_BAD_VALUE;
203	}
204
205	size_t net_buffer_size = buffer->size;
206		// store buffer->size in case buffer freed in KPPP_Interface->Send
207	status_t status = device->KPPP_Interface->Send(buffer, 0x0021); // IP_PROTOCOL 0x0021
208
209	if (status != B_OK) {
210		dprintf("KPPP_Interface->Send(buffer, 0x0021 IP) fail\n");
211		return B_BAD_VALUE;
212	}
213
214	return B_OK;
215}
216
217
218status_t
219ppp_receive_data(net_device *_device, net_buffer **_buffer)
220{
221	TRACE("%s\n", __func__);
222	ppp_device *device = (ppp_device *)_device;
223
224	if (device->KPPP_Interface == NULL)
225		return B_FILE_ERROR;
226
227	TRACE("%s: trying fifo_dequeue_buffer\n", __func__);
228	status_t status = sStackModule->fifo_dequeue_buffer(&(device->ppp_fifo), 0, 10000000, _buffer);
229
230	if (status < B_OK) {
231		TRACE("sorry! can not fifo_dequeue_buffer!\n");
232		return status;
233	}
234
235	// (*_buffer)->interface_address = NULL; // strange need to put here
236
237	return B_OK;
238}
239
240
241status_t
242ppp_set_mtu(net_device *_device, size_t mtu)
243{
244	ppp_device *device = (ppp_device *)_device;
245
246	if (mtu > device->frame_size - ETHER_HEADER_LENGTH - 8
247		|| mtu <= ETHER_HEADER_LENGTH + 8 + 10)
248		return B_BAD_VALUE;
249
250	device->mtu = mtu;
251	return B_OK;
252}
253
254
255status_t
256ppp_set_promiscuous(net_device *_device, bool promiscuous)
257{
258	return B_NOT_SUPPORTED;
259}
260
261
262status_t
263ppp_set_media(net_device *device, uint32 media)
264{
265	return B_NOT_SUPPORTED;
266}
267
268
269status_t
270ppp_add_multicast(struct net_device *_device, const sockaddr *_address)
271{
272	// ppp_device *device = (ppp_device *)_device;
273
274	if (_address->sa_family != AF_LINK)
275		return B_BAD_VALUE;
276
277	const sockaddr_dl *address = (const sockaddr_dl *)_address;
278	if (address->sdl_type != IFT_ETHER)
279		return B_BAD_VALUE;
280
281	return B_NOT_SUPPORTED;
282}
283
284
285status_t
286ppp_remove_multicast(struct net_device *_device, const sockaddr *_address)
287{
288	// ppp_device *device = (ppp_device *)_device;
289
290	if (_address->sa_family != AF_LINK)
291		return B_BAD_VALUE;
292
293	const sockaddr_dl *address = (const sockaddr_dl *)_address;
294	if (address->sdl_type != IFT_ETHER)
295		return B_BAD_VALUE;
296
297	return B_NOT_SUPPORTED;
298}
299
300
301static status_t
302ppp_std_ops(int32 op, ...)
303{
304	switch (op) {
305		case B_MODULE_INIT:
306		{
307			status_t status = get_module(NET_STACK_MODULE_NAME,
308				(module_info **)&sStackModule);
309			if (status < B_OK)
310				return status;
311
312			status = get_module(PPP_INTERFACE_MODULE_NAME,
313				(module_info**)&gPPPInterfaceModule);
314			if (status < B_OK) {
315				put_module(NET_STACK_MODULE_NAME);
316				return status;
317			}
318
319			new (&sCheckList) DoublyLinkedList<ppp_device>;
320				// static C++ objects are not initialized in the module startup
321
322			sLinkCheckerThread = -1;
323
324			sLinkChangeSemaphore = create_sem(0, "ppp link change");
325			if (sLinkChangeSemaphore < B_OK) {
326				put_module(PPP_INTERFACE_MODULE_NAME);
327				put_module(NET_STACK_MODULE_NAME);
328				return sLinkChangeSemaphore;
329			}
330
331			mutex_init(&sListLock, "ppp devices");
332
333			return B_OK;
334		}
335
336		case B_MODULE_UNINIT:
337		{
338			delete_sem(sLinkChangeSemaphore);
339
340			status_t status;
341			wait_for_thread(sLinkCheckerThread, &status);
342
343			mutex_destroy(&sListLock);
344
345			put_module(PPP_INTERFACE_MODULE_NAME);
346			put_module(NET_STACK_MODULE_NAME);
347			return B_OK;
348		}
349
350		default:
351			return B_ERROR;
352	}
353}
354
355
356net_device_module_info spppModule = {
357	{
358		"network/devices/ppp/v1",
359		0,
360		ppp_std_ops
361	},
362	ppp_init,
363	ppp_uninit,
364	ppp_up,
365	ppp_down,
366	ppp_control,
367	ppp_send_data,
368	ppp_receive_data,
369	ppp_set_mtu,
370	ppp_set_promiscuous,
371	ppp_set_media,
372	ppp_add_multicast,
373	ppp_remove_multicast,
374};
375
376
377module_info *modules[] = {
378	(module_info *)&spppModule,
379	NULL
380};
381