xref: /haiku/src/add-ons/kernel/network/devices/loopback/loopback.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2006, 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 <net_buffer.h>
11 #include <net_device.h>
12 #include <net_stack.h>
13 
14 #include <KernelExport.h>
15 
16 #include <net/if.h>
17 #include <net/if_types.h>
18 #include <new>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 
23 struct loopback_device : net_device {
24 	net_fifo	fifo;
25 };
26 
27 
28 struct net_buffer_module_info *gBufferModule;
29 static struct net_stack_module_info *sStackModule;
30 
31 
32 /*!
33 	Swaps \a size bytes of the memory pointed to by \a and \b with each other.
34 */
35 void
36 swap_memory(void *a, void *b, size_t size)
37 {
38 	uint32 *a4 = (uint32 *)a;
39 	uint32 *b4 = (uint32 *)b;
40 	while (size > 4) {
41 		uint32 temp = *a4;
42 		*(a4++) = *b4;
43 		*(b4++) = temp;
44 
45 		size -= 4;
46 	}
47 
48 	uint8 *a1 = (uint8 *)a4;
49 	uint8 *b1 = (uint8 *)b4;
50 	while (size > 0) {
51 		uint8 temp = *a1;
52 		*(a1++) = *b1;
53 		*(b1++) = temp;
54 
55 		size--;
56 	}
57 }
58 
59 
60 //	#pragma mark -
61 
62 
63 status_t
64 loopback_init(const char *name, net_device **_device)
65 {
66 	loopback_device *device;
67 
68 	if (strncmp(name, "loop", 4))
69 		return B_BAD_VALUE;
70 
71 	status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule);
72 	if (status < B_OK)
73 		return status;
74 
75 	status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
76 	if (status < B_OK)
77 		goto err1;
78 
79 	device = new (std::nothrow) loopback_device;
80 	if (device == NULL) {
81 		status = B_NO_MEMORY;
82 		goto err2;
83 	}
84 
85 	memset(device, 0, sizeof(loopback_device));
86 
87 	strcpy(device->name, name);
88 	device->flags = IFF_LOOPBACK;
89 	device->type = IFT_LOOP;
90 	device->mtu = 16384;
91 
92 	*_device = device;
93 	return B_OK;
94 
95 err2:
96 	put_module(NET_BUFFER_MODULE_NAME);
97 err1:
98 	put_module(NET_STACK_MODULE_NAME);
99 	return status;
100 }
101 
102 
103 status_t
104 loopback_uninit(net_device *_device)
105 {
106 	loopback_device *device = (loopback_device *)_device;
107 
108 	put_module(NET_STACK_MODULE_NAME);
109 	put_module(NET_BUFFER_MODULE_NAME);
110 	delete device;
111 
112 	return B_OK;
113 }
114 
115 
116 status_t
117 loopback_up(net_device *_device)
118 {
119 	loopback_device *device = (loopback_device *)_device;
120 	return sStackModule->init_fifo(&device->fifo, "loopback fifo", 65536);
121 }
122 
123 
124 void
125 loopback_down(net_device *_device)
126 {
127 	loopback_device *device = (loopback_device *)_device;
128 	sStackModule->uninit_fifo(&device->fifo);
129 }
130 
131 
132 status_t
133 loopback_control(net_device *device, int32 op, void *argument,
134 	size_t length)
135 {
136 	return B_BAD_VALUE;
137 }
138 
139 
140 status_t
141 loopback_send_data(net_device *_device, net_buffer *buffer)
142 {
143 	loopback_device *device = (loopback_device *)_device;
144 	return sStackModule->fifo_enqueue_buffer(&device->fifo, buffer);
145 }
146 
147 
148 status_t
149 loopback_receive_data(net_device *_device, net_buffer **_buffer)
150 {
151 	loopback_device *device = (loopback_device *)_device;
152 	net_buffer *buffer;
153 
154 	status_t status = sStackModule->fifo_dequeue_buffer(&device->fifo, 0, 0, &buffer);
155 	if (status < B_OK)
156 		return status;
157 
158 	// switch network addresses before delivering
159 	swap_memory(&buffer->source, &buffer->destination,
160 		max_c(buffer->source.ss_len, buffer->destination.ss_len));
161 
162 	*_buffer = buffer;
163 	return B_OK;
164 }
165 
166 
167 status_t
168 loopback_set_mtu(net_device *device, size_t mtu)
169 {
170 	if (mtu > 65536
171 		|| mtu < 16)
172 		return B_BAD_VALUE;
173 
174 	device->mtu = mtu;
175 	return B_OK;
176 }
177 
178 
179 status_t
180 loopback_set_promiscuous(net_device *device, bool promiscuous)
181 {
182 	return EOPNOTSUPP;
183 }
184 
185 
186 status_t
187 loopback_set_media(net_device *device, uint32 media)
188 {
189 	return EOPNOTSUPP;
190 }
191 
192 
193 static status_t
194 loopback_std_ops(int32 op, ...)
195 {
196 	switch (op) {
197 		case B_MODULE_INIT:
198 		case B_MODULE_UNINIT:
199 			return B_OK;
200 
201 		default:
202 			return B_ERROR;
203 	}
204 }
205 
206 
207 net_device_module_info sLoopbackModule = {
208 	{
209 		"network/devices/loopback/v1",
210 		0,
211 		loopback_std_ops
212 	},
213 	loopback_init,
214 	loopback_uninit,
215 	loopback_up,
216 	loopback_down,
217 	loopback_control,
218 	loopback_send_data,
219 	loopback_receive_data,
220 	loopback_set_mtu,
221 	loopback_set_promiscuous,
222 	loopback_set_media,
223 };
224 
225 module_info *modules[] = {
226 	(module_info *)&sLoopbackModule,
227 	NULL
228 };
229