xref: /haiku/src/add-ons/kernel/network/devices/ethernet/ethernet.cpp (revision 9ecf9d1c1d4888d341a6eac72112c72d1ae3a4cb)
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 <ether_driver.h>
11 #include <ethernet.h>
12 #include <net_buffer.h>
13 #include <net_device.h>
14 
15 #include <KernelExport.h>
16 
17 #include <errno.h>
18 #include <net/if.h>
19 #include <net/if_types.h>
20 #include <net/if_dl.h>
21 #include <new>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 
26 struct ethernet_device : net_device {
27 	int		fd;
28 	uint32	frame_size;
29 };
30 
31 
32 struct net_buffer_module_info *sBufferModule;
33 
34 
35 status_t
36 ethernet_init(const char *name, net_device **_device)
37 {
38 	// make sure this is a device in /dev/net, but not the
39 	// networking (userland) stack driver
40 	if (strncmp(name, "/dev/net/", 9) || !strcmp(name, "/dev/net/stack")
41 		|| !strcmp(name, "/dev/net/userland_server"))
42 		return B_BAD_VALUE;
43 
44 	status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&sBufferModule);
45 	if (status < B_OK)
46 		return status;
47 
48 	ethernet_device *device = new (std::nothrow) ethernet_device;
49 	if (device == NULL) {
50 		put_module(NET_BUFFER_MODULE_NAME);
51 		return B_NO_MEMORY;
52 	}
53 
54 	memset(device, 0, sizeof(ethernet_device));
55 
56 	strcpy(device->name, name);
57 	device->flags = IFF_BROADCAST;
58 	device->type = IFT_ETHER;
59 	device->mtu = 1500;
60 	device->header_length = ETHER_HEADER_LENGTH;
61 	device->fd = -1;
62 
63 	*_device = device;
64 	return B_OK;
65 }
66 
67 
68 status_t
69 ethernet_uninit(net_device *device)
70 {
71 	put_module(NET_BUFFER_MODULE_NAME);
72 	delete device;
73 
74 	return B_OK;
75 }
76 
77 
78 status_t
79 ethernet_up(net_device *_device)
80 {
81 	ethernet_device *device = (ethernet_device *)_device;
82 
83 	device->fd = open(device->name, O_RDWR);
84 	if (device->fd < 0)
85 		return errno;
86 
87 	ether_init_params params;
88 	memset(&params, 0, sizeof(ether_init_params));
89 	if (ioctl(device->fd, ETHER_INIT, &params, sizeof(ether_init_params)) < 0)
90 		goto err;
91 
92 	if (ioctl(device->fd, ETHER_GETADDR, device->address.data, ETHER_ADDRESS_LENGTH) < 0)
93 		goto err;
94 
95 	if (ioctl(device->fd, ETHER_GETFRAMESIZE, &device->frame_size, sizeof(uint32)) < 0) {
96 		// this call is obviously optional
97 		device->frame_size = ETHER_MAX_FRAME_SIZE;
98 	}
99 
100 	device->address.length = ETHER_ADDRESS_LENGTH;
101 	device->mtu = device->frame_size - device->header_length;
102 	return B_OK;
103 
104 err:
105 	close(device->fd);
106 	device->fd = -1;
107 	return errno;
108 }
109 
110 
111 void
112 ethernet_down(net_device *_device)
113 {
114 	ethernet_device *device = (ethernet_device *)_device;
115 	close(device->fd);
116 }
117 
118 
119 status_t
120 ethernet_control(net_device *_device, int32 op, void *argument,
121 	size_t length)
122 {
123 	ethernet_device *device = (ethernet_device *)_device;
124 	return ioctl(device->fd, op, argument, length);
125 }
126 
127 
128 status_t
129 ethernet_send_data(net_device *_device, net_buffer *buffer)
130 {
131 	ethernet_device *device = (ethernet_device *)_device;
132 
133 dprintf("try to send ethernet packet of %lu bytes (flags %ld):\n", buffer->size, buffer->flags);
134 	if (buffer->size > device->frame_size || buffer->size < ETHER_HEADER_LENGTH)
135 		return B_BAD_VALUE;
136 
137 	if (sBufferModule->count_iovecs(buffer) > 1) {
138 		dprintf("scattered I/O is not yet supported by ethernet device.\n");
139 		return B_NOT_SUPPORTED;
140 	}
141 
142 	struct iovec iovec;
143 	sBufferModule->get_iovecs(buffer, &iovec, 1);
144 
145 dump_block((const char *)iovec.iov_base, buffer->size, "  ");
146 	ssize_t bytesWritten = write(device->fd, iovec.iov_base, iovec.iov_len);
147 dprintf("sent: %ld\n", bytesWritten);
148 	if (bytesWritten < 0) {
149 		device->stats.send.errors++;
150 		return bytesWritten;
151 	}
152 
153 	device->stats.send.packets++;
154 	device->stats.send.bytes += bytesWritten;
155 
156 	sBufferModule->free(buffer);
157 	return B_OK;
158 }
159 
160 
161 status_t
162 ethernet_receive_data(net_device *_device, net_buffer **_buffer)
163 {
164 	ethernet_device *device = (ethernet_device *)_device;
165 
166 	// TODO: better header space
167 	net_buffer *buffer = sBufferModule->create(256);
168 	if (buffer == NULL)
169 		return ENOBUFS;
170 
171 	// TODO: this only works for standard ethernet frames - we need iovecs
172 	//	for jumbo frame support (or a separate read buffer)!
173 	//	It would be even nicer to get net_buffers from the ethernet driver
174 	//	directly.
175 
176 	ssize_t bytesRead;
177 	void *data;
178 
179 	status_t status = sBufferModule->append_size(buffer, device->frame_size, &data);
180 	if (status == B_OK && data == NULL) {
181 		dprintf("scattered I/O is not yet supported by ethernet device.\n");
182 		status = B_NOT_SUPPORTED;
183 	}
184 	if (status < B_OK)
185 		goto err;
186 
187 	bytesRead = read(device->fd, data, device->frame_size);
188 	if (bytesRead < 0) {
189 		device->stats.receive.errors++;
190 		status = bytesRead;
191 		goto err;
192 	}
193 
194 	status = sBufferModule->trim(buffer, bytesRead);
195 	if (status < B_OK) {
196 		device->stats.receive.dropped++;
197 		goto err;
198 	}
199 
200 	device->stats.receive.bytes += bytesRead;
201 	device->stats.receive.packets++;
202 
203 	*_buffer = buffer;
204 	return B_OK;
205 
206 err:
207 	sBufferModule->free(buffer);
208 	return status;
209 }
210 
211 
212 status_t
213 ethernet_set_mtu(net_device *_device, size_t mtu)
214 {
215 	ethernet_device *device = (ethernet_device *)_device;
216 
217 	if (mtu > device->frame_size - ETHER_HEADER_LENGTH
218 		|| mtu <= ETHER_HEADER_LENGTH + 10)
219 		return B_BAD_VALUE;
220 
221 	device->mtu = mtu;
222 	return B_OK;
223 }
224 
225 
226 status_t
227 ethernet_set_promiscuous(net_device *device, bool promiscuous)
228 {
229 	return EOPNOTSUPP;
230 }
231 
232 
233 status_t
234 ethernet_set_media(net_device *device, uint32 media)
235 {
236 	return EOPNOTSUPP;
237 }
238 
239 
240 status_t
241 ethernet_get_multicast_addrs(struct net_device *device,
242 	net_hardware_address **addressArray, uint32 count)
243 {
244 	return EOPNOTSUPP;
245 }
246 
247 
248 status_t
249 ethernet_set_multicast_addrs(struct net_device *device,
250 	const net_hardware_address **addressArray, uint32 count)
251 {
252 	return EOPNOTSUPP;
253 }
254 
255 
256 static status_t
257 ethernet_std_ops(int32 op, ...)
258 {
259 	switch (op) {
260 		case B_MODULE_INIT:
261 		case B_MODULE_UNINIT:
262 			return B_OK;
263 
264 		default:
265 			return B_ERROR;
266 	}
267 }
268 
269 
270 net_device_module_info sEthernetModule = {
271 	{
272 		"network/devices/ethernet/v1",
273 		0,
274 		ethernet_std_ops
275 	},
276 	ethernet_init,
277 	ethernet_uninit,
278 	ethernet_up,
279 	ethernet_down,
280 	ethernet_control,
281 	ethernet_send_data,
282 	ethernet_receive_data,
283 	ethernet_set_mtu,
284 	ethernet_set_promiscuous,
285 	ethernet_set_media,
286 	ethernet_get_multicast_addrs,
287 	ethernet_set_multicast_addrs
288 };
289 
290 module_info *modules[] = {
291 	(module_info *)&sEthernetModule,
292 	NULL
293 };
294