1/*
2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 */
8
9
10#include <ethernet.h>
11#include <net_datalink_protocol.h>
12#include <net_device.h>
13#include <net_datalink.h>
14#include <net_stack.h>
15#include <NetBufferUtilities.h>
16
17#include <ByteOrder.h>
18#include <KernelExport.h>
19
20#include <net/if.h>
21#include <net/if_types.h>
22#include <net/if_dl.h>
23#include <new>
24#include <string.h>
25
26
27struct loopback_frame_protocol : net_datalink_protocol {
28};
29
30
31struct net_buffer_module_info* gBufferModule;
32
33
34status_t
35loopback_deframe(net_device* device, net_buffer* buffer)
36{
37	// there is not that much to do...
38	return B_OK;
39}
40
41
42//	#pragma mark -
43
44
45status_t
46loopback_frame_init(struct net_interface*interface, net_domain* domain,
47	net_datalink_protocol** _protocol)
48{
49	if (interface->device->type != IFT_LOOP && interface->device->type != IFT_TUNNEL)
50		return B_BAD_TYPE;
51
52	loopback_frame_protocol* protocol;
53
54	net_stack_module_info* stack;
55	status_t status = get_module(NET_STACK_MODULE_NAME, (module_info**)&stack);
56	if (status != B_OK)
57		return status;
58	status = stack->register_device_deframer(interface->device,
59		&loopback_deframe);
60	if (status != B_OK)
61		goto err1;
62
63	if (interface->device->type == IFT_LOOP) {
64		// Locally received buffers don't need a domain device handler, as the
65		// buffer reception is handled internally.
66	} else if (interface->device->type == IFT_TUNNEL) {
67		status = stack->register_domain_device_handler(
68			interface->device, B_NET_FRAME_TYPE_IPV4, domain);
69		if (status != B_OK)
70			return status;
71	}
72
73	protocol = new(std::nothrow) loopback_frame_protocol;
74	if (protocol == NULL) {
75		status = B_NO_MEMORY;
76		goto err2;
77	}
78
79	put_module(NET_STACK_MODULE_NAME);
80
81	*_protocol = protocol;
82	return B_OK;
83
84err2:
85	stack->unregister_device_deframer(interface->device);
86err1:
87	put_module(NET_STACK_MODULE_NAME);
88	return status;
89}
90
91
92status_t
93loopback_frame_uninit(net_datalink_protocol* protocol)
94{
95	net_stack_module_info* stack;
96	if (get_module(NET_STACK_MODULE_NAME, (module_info**)&stack) == B_OK) {
97		stack->unregister_device_deframer(protocol->interface->device);
98		stack->unregister_device_handler(protocol->interface->device, 0);
99		put_module(NET_STACK_MODULE_NAME);
100	}
101
102	delete protocol;
103	return B_OK;
104}
105
106
107status_t
108loopback_frame_send_data(net_datalink_protocol* protocol, net_buffer* buffer)
109{
110	return protocol->next->module->send_data(protocol->next, buffer);
111}
112
113
114status_t
115loopback_frame_up(net_datalink_protocol* protocol)
116{
117	return protocol->next->module->interface_up(protocol->next);
118}
119
120
121void
122loopback_frame_down(net_datalink_protocol* protocol)
123{
124	return protocol->next->module->interface_down(protocol->next);
125}
126
127
128status_t
129loopback_frame_change_address(net_datalink_protocol* protocol,
130	net_interface_address* address, int32 option,
131	const struct sockaddr* oldAddress, const struct sockaddr* newAddress)
132{
133	return protocol->next->module->change_address(protocol->next, address,
134		option, oldAddress, newAddress);
135}
136
137
138status_t
139loopback_frame_control(net_datalink_protocol* protocol, int32 option,
140	void* argument, size_t length)
141{
142	return protocol->next->module->control(protocol->next, option, argument,
143		length);
144}
145
146
147static status_t
148loopback_frame_join_multicast(net_datalink_protocol* protocol,
149	const sockaddr* address)
150{
151	return protocol->next->module->join_multicast(protocol->next, address);
152}
153
154
155static status_t
156loopback_frame_leave_multicast(net_datalink_protocol* protocol,
157	const sockaddr* address)
158{
159	return protocol->next->module->leave_multicast(protocol->next, address);
160}
161
162
163static status_t
164loopback_frame_std_ops(int32 op, ...)
165{
166	switch (op) {
167		case B_MODULE_INIT:
168			return get_module(NET_BUFFER_MODULE_NAME,
169				(module_info**)&gBufferModule);
170		case B_MODULE_UNINIT:
171			put_module(NET_BUFFER_MODULE_NAME);
172			return B_OK;
173
174		default:
175			return B_ERROR;
176	}
177}
178
179
180static net_datalink_protocol_module_info sLoopbackFrameModule = {
181	{
182		"network/datalink_protocols/loopback_frame/v1",
183		0,
184		loopback_frame_std_ops
185	},
186	loopback_frame_init,
187	loopback_frame_uninit,
188	loopback_frame_send_data,
189	loopback_frame_up,
190	loopback_frame_down,
191	loopback_frame_change_address,
192	loopback_frame_control,
193	loopback_frame_join_multicast,
194	loopback_frame_leave_multicast,
195};
196
197module_info* modules[] = {
198	(module_info*)&sLoopbackFrameModule,
199	NULL
200};
201