xref: /haiku/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp (revision e0ef64750f3169cd634bb2f7a001e22488b05231)
1 /*
2  * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <net_datalink.h>
8 #include <net_protocol.h>
9 #include <net_stack.h>
10 #include <net_datalink_protocol.h>
11 #include <NetUtilities.h>
12 #include <NetBufferUtilities.h>
13 
14 #include <KernelExport.h>
15 #include <util/list.h>
16 
17 #include <netinet/icmp6.h>
18 #include <netinet/in.h>
19 #include <new>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <ipv6_datagram/ndp.h>
24 
25 
26 #define TRACE_ICMP6
27 #ifdef TRACE_ICMP6
28 #	define TRACE(x) dprintf x
29 #else
30 #	define TRACE(x) ;
31 #endif
32 
33 
34 typedef NetBufferField<uint16, offsetof(icmp6_hdr, icmp6_cksum)> ICMP6ChecksumField;
35 
36 
37 net_buffer_module_info *gBufferModule;
38 static net_stack_module_info *sStackModule;
39 static net_ndp_module_info *sIPv6NDPModule;
40 
41 
42 net_protocol *
43 icmp6_init_protocol(net_socket *socket)
44 {
45 	net_protocol *protocol = new (std::nothrow) net_protocol;
46 	if (protocol == NULL)
47 		return NULL;
48 
49 	return protocol;
50 }
51 
52 
53 status_t
54 icmp6_uninit_protocol(net_protocol *protocol)
55 {
56 	delete protocol;
57 	return B_OK;
58 }
59 
60 
61 status_t
62 icmp6_open(net_protocol *protocol)
63 {
64 	return B_OK;
65 }
66 
67 
68 status_t
69 icmp6_close(net_protocol *protocol)
70 {
71 	return B_OK;
72 }
73 
74 
75 status_t
76 icmp6_free(net_protocol *protocol)
77 {
78 	return B_OK;
79 }
80 
81 
82 status_t
83 icmp6_connect(net_protocol *protocol, const struct sockaddr *address)
84 {
85 	return B_ERROR;
86 }
87 
88 
89 status_t
90 icmp6_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
91 {
92 	return EOPNOTSUPP;
93 }
94 
95 
96 status_t
97 icmp6_control(net_protocol *protocol, int level, int option, void *value,
98 	size_t *_length)
99 {
100 	return protocol->next->module->control(protocol->next, level, option,
101 		value, _length);
102 }
103 
104 
105 status_t
106 icmp6_getsockopt(net_protocol *protocol, int level, int option,
107 	void *value, int *length)
108 {
109 	return protocol->next->module->getsockopt(protocol->next, level, option,
110 		value, length);
111 }
112 
113 
114 status_t
115 icmp6_setsockopt(net_protocol *protocol, int level, int option,
116 	const void *value, int length)
117 {
118 	return protocol->next->module->setsockopt(protocol->next, level, option,
119 		value, length);
120 }
121 
122 
123 status_t
124 icmp6_bind(net_protocol *protocol, const struct sockaddr *address)
125 {
126 	return B_ERROR;
127 }
128 
129 
130 status_t
131 icmp6_unbind(net_protocol *protocol, struct sockaddr *address)
132 {
133 	return B_ERROR;
134 }
135 
136 
137 status_t
138 icmp6_listen(net_protocol *protocol, int count)
139 {
140 	return EOPNOTSUPP;
141 }
142 
143 
144 status_t
145 icmp6_shutdown(net_protocol *protocol, int direction)
146 {
147 	return EOPNOTSUPP;
148 }
149 
150 
151 status_t
152 icmp6_send_data(net_protocol *protocol, net_buffer *buffer)
153 {
154 	return protocol->next->module->send_data(protocol->next, buffer);
155 }
156 
157 
158 status_t
159 icmp6_send_routed_data(net_protocol *protocol, struct net_route *route,
160 	net_buffer *buffer)
161 {
162 	return protocol->next->module->send_routed_data(protocol->next, route, buffer);
163 }
164 
165 
166 ssize_t
167 icmp6_send_avail(net_protocol *protocol)
168 {
169 	return B_ERROR;
170 }
171 
172 
173 status_t
174 icmp6_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
175 	net_buffer **_buffer)
176 {
177 	return B_ERROR;
178 }
179 
180 
181 ssize_t
182 icmp6_read_avail(net_protocol *protocol)
183 {
184 	return B_ERROR;
185 }
186 
187 
188 struct net_domain *
189 icmp6_get_domain(net_protocol *protocol)
190 {
191 	return protocol->next->module->get_domain(protocol->next);
192 }
193 
194 
195 size_t
196 icmp6_get_mtu(net_protocol *protocol, const struct sockaddr *address)
197 {
198 	return protocol->next->module->get_mtu(protocol->next, address);
199 }
200 
201 
202 static net_domain*
203 get_domain(struct net_buffer* buffer)
204 {
205 	net_domain* domain;
206 	if (buffer->interface_address != NULL)
207 		domain = buffer->interface_address->domain;
208 	else
209 		domain = sStackModule->get_domain(buffer->source->sa_family);
210 
211 	if (domain == NULL || domain->module == NULL)
212 		return NULL;
213 
214 	return domain;
215 }
216 
217 
218 status_t
219 icmp6_receive_data(net_buffer *buffer)
220 {
221 	TRACE(("ICMPv6 received some data, buffer length %lu\n", buffer->size));
222 
223 	net_domain* domain = get_domain(buffer);
224 	if (domain == NULL)
225 		return B_ERROR;
226 
227 	NetBufferHeaderReader<icmp6_hdr> bufferHeader(buffer);
228 	if (bufferHeader.Status() < B_OK)
229 		return bufferHeader.Status();
230 
231 	icmp6_hdr &header = bufferHeader.Data();
232 
233 	TRACE(("  got type %u, code %u, checksum 0x%x\n", header.icmp6_type,
234 			header.icmp6_code, header.icmp6_cksum));
235 
236 	net_address_module_info* addressModule = domain->address_module;
237 
238 	// compute and check the checksum
239  	if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer,
240  			IPPROTO_ICMPV6) != 0)
241  		return B_BAD_DATA;
242 
243 	switch (header.icmp6_type) {
244 		case ICMP6_ECHO_REPLY:
245 			break;
246 
247 		case ICMP6_ECHO_REQUEST:
248 		{
249 			if (buffer->interface_address != NULL) {
250 				// We only reply to echo requests of our local interface; we
251 				// don't reply to broadcast requests
252 				if (!domain->address_module->equal_addresses(
253 						buffer->interface_address->local, buffer->destination))
254 					break;
255 			}
256 
257 			net_buffer *reply = gBufferModule->duplicate(buffer);
258 			if (reply == NULL)
259 				return B_NO_MEMORY;
260 
261 			gBufferModule->swap_addresses(reply);
262 
263 			// There already is an ICMP header, and we'll reuse it
264 			NetBufferHeaderReader<icmp6_hdr> header(reply);
265 
266 			header->icmp6_type = ICMP6_ECHO_REPLY;
267 			header->icmp6_code = 0;
268 			header->icmp6_cksum = 0;
269 
270 			header.Sync();
271 
272 			*ICMP6ChecksumField(reply) = Checksum::PseudoHeader(addressModule,
273 				gBufferModule, buffer, IPPROTO_ICMPV6);
274 
275 			status_t status = domain->module->send_data(NULL, reply);
276 			if (status < B_OK) {
277 				gBufferModule->free(reply);
278 				return status;
279 			}
280 		}
281 
282 		default:
283 			// unrecognized messages go to neighbor discovery protocol handler
284 			return sIPv6NDPModule->receive_data(buffer);
285 	}
286 
287 	gBufferModule->free(buffer);
288 	return B_OK;
289 }
290 
291 
292 status_t
293 icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
294 {
295 	// TODO: does this look OK?
296 	return icmp6_receive_data(buffer);
297 }
298 
299 
300 status_t
301 icmp6_error_received(net_error code, net_buffer* data)
302 {
303  	return B_ERROR;
304 }
305 
306 
307 status_t
308 icmp6_error_reply(net_protocol* protocol, net_buffer* buffer, net_error error,
309 	net_error_data* errorData)
310 {
311 	return B_ERROR;
312 }
313 
314 
315 //	#pragma mark -
316 
317 
318 static status_t
319 icmp6_init()
320 {
321 	sStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6,
322 		"network/protocols/icmp6/v1",
323 		"network/protocols/ipv6/v1",
324 		NULL);
325 
326 	sStackModule->register_domain_receiving_protocol(AF_INET6, IPPROTO_ICMPV6,
327 		"network/protocols/icmp6/v1");
328 
329 	return B_OK;
330 }
331 
332 
333 static status_t
334 icmp6_std_ops(int32 op, ...)
335 {
336 	switch (op) {
337 		case B_MODULE_INIT:
338 			return icmp6_init();
339 
340 		case B_MODULE_UNINIT:
341 			return B_OK;
342 
343 		default:
344 			return B_ERROR;
345 	}
346 }
347 
348 
349 net_protocol_module_info sICMP6Module = {
350 	{
351 		"network/protocols/icmp6/v1",
352 		0,
353 		icmp6_std_ops
354 	},
355 	NET_PROTOCOL_ATOMIC_MESSAGES,
356 
357 	icmp6_init_protocol,
358 	icmp6_uninit_protocol,
359 	icmp6_open,
360 	icmp6_close,
361 	icmp6_free,
362 	icmp6_connect,
363 	icmp6_accept,
364 	icmp6_control,
365 	icmp6_getsockopt,
366 	icmp6_setsockopt,
367 	icmp6_bind,
368 	icmp6_unbind,
369 	icmp6_listen,
370 	icmp6_shutdown,
371 	icmp6_send_data,
372 	icmp6_send_routed_data,
373 	icmp6_send_avail,
374 	icmp6_read_data,
375 	icmp6_read_avail,
376 	icmp6_get_domain,
377 	icmp6_get_mtu,
378 	icmp6_receive_data,
379 	icmp6_deliver_data,
380 	icmp6_error_received,
381 	icmp6_error_reply,
382 	NULL,		// add_ancillary_data()
383 	NULL,		// process_ancillary_data()
384 	NULL,		// process_ancillary_data_no_container()
385 	NULL,		// send_data_no_buffer()
386 	NULL		// read_data_no_buffer()
387 };
388 
389 module_dependency module_dependencies[] = {
390 	{NET_STACK_MODULE_NAME, (module_info **)&sStackModule},
391 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
392 	{"network/datalink_protocols/ipv6_datagram/ndp/v1",
393 		(module_info **)&sIPv6NDPModule},
394 	{}
395 };
396 
397 module_info *modules[] = {
398 	(module_info *)&sICMP6Module,
399 	NULL
400 };
401