xref: /haiku/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
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 %" B_PRIu32 "\n",
222 		buffer->size));
223 
224 	net_domain* domain = get_domain(buffer);
225 	if (domain == NULL)
226 		return B_ERROR;
227 
228 	NetBufferHeaderReader<icmp6_hdr> bufferHeader(buffer);
229 	if (bufferHeader.Status() < B_OK)
230 		return bufferHeader.Status();
231 
232 	icmp6_hdr &header = bufferHeader.Data();
233 
234 	TRACE(("  got type %u, code %u, checksum 0x%x\n", header.icmp6_type,
235 			header.icmp6_code, header.icmp6_cksum));
236 
237 	net_address_module_info* addressModule = domain->address_module;
238 
239 	// compute and check the checksum
240  	if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer,
241  			IPPROTO_ICMPV6) != 0)
242  		return B_BAD_DATA;
243 
244 	switch (header.icmp6_type) {
245 		case ICMP6_ECHO_REPLY:
246 			break;
247 
248 		case ICMP6_ECHO_REQUEST:
249 		{
250 			if (buffer->interface_address != NULL) {
251 				// We only reply to echo requests of our local interface; we
252 				// don't reply to broadcast requests
253 				if (!domain->address_module->equal_addresses(
254 						buffer->interface_address->local, buffer->destination))
255 					break;
256 			}
257 
258 			net_buffer *reply = gBufferModule->duplicate(buffer);
259 			if (reply == NULL)
260 				return B_NO_MEMORY;
261 
262 			gBufferModule->swap_addresses(reply);
263 
264 			// There already is an ICMP header, and we'll reuse it
265 			NetBufferHeaderReader<icmp6_hdr> header(reply);
266 
267 			header->icmp6_type = ICMP6_ECHO_REPLY;
268 			header->icmp6_code = 0;
269 			header->icmp6_cksum = 0;
270 
271 			header.Sync();
272 
273 			*ICMP6ChecksumField(reply) = Checksum::PseudoHeader(addressModule,
274 				gBufferModule, buffer, IPPROTO_ICMPV6);
275 
276 			status_t status = domain->module->send_data(NULL, reply);
277 			if (status < B_OK) {
278 				gBufferModule->free(reply);
279 				return status;
280 			}
281 		}
282 
283 		default:
284 			// unrecognized messages go to neighbor discovery protocol handler
285 			return sIPv6NDPModule->receive_data(buffer);
286 	}
287 
288 	gBufferModule->free(buffer);
289 	return B_OK;
290 }
291 
292 
293 status_t
294 icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
295 {
296 	// TODO: does this look OK?
297 	return icmp6_receive_data(buffer);
298 }
299 
300 
301 status_t
302 icmp6_error_received(net_error code, net_buffer* data)
303 {
304  	return B_ERROR;
305 }
306 
307 
308 status_t
309 icmp6_error_reply(net_protocol* protocol, net_buffer* buffer, net_error error,
310 	net_error_data* errorData)
311 {
312 	return B_ERROR;
313 }
314 
315 
316 //	#pragma mark -
317 
318 
319 static status_t
320 icmp6_init()
321 {
322 	sStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6,
323 		"network/protocols/icmp6/v1",
324 		"network/protocols/ipv6/v1",
325 		NULL);
326 
327 	sStackModule->register_domain_receiving_protocol(AF_INET6, IPPROTO_ICMPV6,
328 		"network/protocols/icmp6/v1");
329 
330 	return B_OK;
331 }
332 
333 
334 static status_t
335 icmp6_std_ops(int32 op, ...)
336 {
337 	switch (op) {
338 		case B_MODULE_INIT:
339 			return icmp6_init();
340 
341 		case B_MODULE_UNINIT:
342 			return B_OK;
343 
344 		default:
345 			return B_ERROR;
346 	}
347 }
348 
349 
350 net_protocol_module_info sICMP6Module = {
351 	{
352 		"network/protocols/icmp6/v1",
353 		0,
354 		icmp6_std_ops
355 	},
356 	NET_PROTOCOL_ATOMIC_MESSAGES,
357 
358 	icmp6_init_protocol,
359 	icmp6_uninit_protocol,
360 	icmp6_open,
361 	icmp6_close,
362 	icmp6_free,
363 	icmp6_connect,
364 	icmp6_accept,
365 	icmp6_control,
366 	icmp6_getsockopt,
367 	icmp6_setsockopt,
368 	icmp6_bind,
369 	icmp6_unbind,
370 	icmp6_listen,
371 	icmp6_shutdown,
372 	icmp6_send_data,
373 	icmp6_send_routed_data,
374 	icmp6_send_avail,
375 	icmp6_read_data,
376 	icmp6_read_avail,
377 	icmp6_get_domain,
378 	icmp6_get_mtu,
379 	icmp6_receive_data,
380 	icmp6_deliver_data,
381 	icmp6_error_received,
382 	icmp6_error_reply,
383 	NULL,		// add_ancillary_data()
384 	NULL,		// process_ancillary_data()
385 	NULL,		// process_ancillary_data_no_container()
386 	NULL,		// send_data_no_buffer()
387 	NULL		// read_data_no_buffer()
388 };
389 
390 module_dependency module_dependencies[] = {
391 	{NET_STACK_MODULE_NAME, (module_info **)&sStackModule},
392 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
393 	{"network/datalink_protocols/ipv6_datagram/ndp/v1",
394 		(module_info **)&sIPv6NDPModule},
395 	{}
396 };
397 
398 module_info *modules[] = {
399 	(module_info *)&sICMP6Module,
400 	NULL
401 };
402