155682Smarkm/*
2233294Sstas * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3233294Sstas * Distributed under the terms of the MIT License.
4233294Sstas */
555682Smarkm
6233294Sstas
7233294Sstas#include <net_datalink.h>
8233294Sstas#include <net_protocol.h>
955682Smarkm#include <net_stack.h>
10233294Sstas#include <net_datalink_protocol.h>
11233294Sstas#include <NetUtilities.h>
1255682Smarkm#include <NetBufferUtilities.h>
13233294Sstas
14233294Sstas#include <KernelExport.h>
15233294Sstas#include <util/list.h>
1655682Smarkm
17233294Sstas#include <netinet/icmp6.h>
18233294Sstas#include <netinet/in.h>
19233294Sstas#include <new>
2055682Smarkm#include <stdlib.h>
21233294Sstas#include <string.h>
22233294Sstas
23233294Sstas#include <ipv6_datagram/ndp.h>
24233294Sstas
25233294Sstas
26233294Sstas//#define TRACE_ICMP6
27233294Sstas#ifdef TRACE_ICMP6
28233294Sstas#	define TRACE(x) dprintf x
29233294Sstas#else
30233294Sstas#	define TRACE(x) ;
31233294Sstas#endif
3255682Smarkm
3355682Smarkm
3455682Smarkmtypedef NetBufferField<uint16, offsetof(icmp6_hdr, icmp6_cksum)> ICMP6ChecksumField;
35178825Sdfr
3655682Smarkm
3755682Smarkmnet_buffer_module_info *gBufferModule;
3857416Smarkmstatic net_stack_module_info *sStackModule;
3955682Smarkmstatic net_ndp_module_info *sIPv6NDPModule;
4055682Smarkm
4155682Smarkm
4255682Smarkmnet_protocol *
4355682Smarkmicmp6_init_protocol(net_socket *socket)
4455682Smarkm{
4555682Smarkm	net_protocol *protocol = new (std::nothrow) net_protocol;
4655682Smarkm	if (protocol == NULL)
4755682Smarkm		return NULL;
4855682Smarkm
4990926Snectar	return protocol;
50178825Sdfr}
5155682Smarkm
5255682Smarkm
5355682Smarkmstatus_t
5455682Smarkmicmp6_uninit_protocol(net_protocol *protocol)
5555682Smarkm{
56233294Sstas	delete protocol;
5755682Smarkm	return B_OK;
5855682Smarkm}
5957416Smarkm
6057416Smarkm
6155682Smarkmstatus_t
6255682Smarkmicmp6_open(net_protocol *protocol)
6355682Smarkm{
6457416Smarkm	return B_OK;
6557416Smarkm}
6657416Smarkm
6757416Smarkm
6857416Smarkmstatus_t
6957416Smarkmicmp6_close(net_protocol *protocol)
7057416Smarkm{
7157416Smarkm	return B_OK;
7257416Smarkm}
7355682Smarkm
7455682Smarkm
7555682Smarkmstatus_t
7657416Smarkmicmp6_free(net_protocol *protocol)
7755682Smarkm{
7857416Smarkm	return B_OK;
79233294Sstas}
8057416Smarkm
8157416Smarkm
8257416Smarkmstatus_t
8357416Smarkmicmp6_connect(net_protocol *protocol, const struct sockaddr *address)
8457416Smarkm{
8557416Smarkm	return B_ERROR;
8657416Smarkm}
8757416Smarkm
8855682Smarkm
8955682Smarkmstatus_t
9057416Smarkmicmp6_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
9155682Smarkm{
9255682Smarkm	return EOPNOTSUPP;
9357416Smarkm}
9457416Smarkm
9557416Smarkm
9657416Smarkmstatus_t
9757416Smarkmicmp6_control(net_protocol *protocol, int level, int option, void *value,
9857416Smarkm	size_t *_length)
9955682Smarkm{
10057416Smarkm	return protocol->next->module->control(protocol->next, level, option,
10157416Smarkm		value, _length);
10257416Smarkm}
10357416Smarkm
10457416Smarkm
10557416Smarkmstatus_t
10657416Smarkmicmp6_getsockopt(net_protocol *protocol, int level, int option,
10757416Smarkm	void *value, int *length)
10857416Smarkm{
10957416Smarkm	return protocol->next->module->getsockopt(protocol->next, level, option,
11057416Smarkm		value, length);
11157416Smarkm}
11257416Smarkm
11357416Smarkm
11457416Smarkmstatus_t
11557416Smarkmicmp6_setsockopt(net_protocol *protocol, int level, int option,
11657416Smarkm	const void *value, int length)
11757416Smarkm{
11857416Smarkm	return protocol->next->module->setsockopt(protocol->next, level, option,
119178825Sdfr		value, length);
12057416Smarkm}
12155682Smarkm
12257416Smarkm
12357416Smarkmstatus_t
12457416Smarkmicmp6_bind(net_protocol *protocol, const struct sockaddr *address)
12557416Smarkm{
12655682Smarkm	return B_ERROR;
12755682Smarkm}
12857416Smarkm
129178825Sdfr
13057416Smarkmstatus_t
131178825Sdfricmp6_unbind(net_protocol *protocol, struct sockaddr *address)
13257416Smarkm{
13357416Smarkm	return B_ERROR;
13457416Smarkm}
13557416Smarkm
13657416Smarkm
13757416Smarkmstatus_t
13857416Smarkmicmp6_listen(net_protocol *protocol, int count)
13957416Smarkm{
14057416Smarkm	return EOPNOTSUPP;
14157416Smarkm}
14257416Smarkm
14357416Smarkm
14457416Smarkmstatus_t
14557416Smarkmicmp6_shutdown(net_protocol *protocol, int direction)
14657416Smarkm{
14757416Smarkm	return EOPNOTSUPP;
14857416Smarkm}
14957416Smarkm
15057416Smarkm
15155682Smarkmstatus_t
15255682Smarkmicmp6_send_data(net_protocol *protocol, net_buffer *buffer)
15357416Smarkm{
15455682Smarkm	return protocol->next->module->send_data(protocol->next, buffer);
15555682Smarkm}
156233294Sstas
157233294Sstas
15855682Smarkmstatus_t
15957416Smarkmicmp6_send_routed_data(net_protocol *protocol, struct net_route *route,
16057416Smarkm	net_buffer *buffer)
16155682Smarkm{
16255682Smarkm	return protocol->next->module->send_routed_data(protocol->next, route, buffer);
16355682Smarkm}
16455682Smarkm
165233294Sstas
16655682Smarkmssize_t
16755682Smarkmicmp6_send_avail(net_protocol *protocol)
16857416Smarkm{
16955682Smarkm	return B_ERROR;
17055682Smarkm}
17155682Smarkm
17255682Smarkm
17355682Smarkmstatus_t
17455682Smarkmicmp6_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
17555682Smarkm	net_buffer **_buffer)
17655682Smarkm{
17755682Smarkm	return B_ERROR;
17855682Smarkm}
17957416Smarkm
18057416Smarkm
18155682Smarkmssize_t
18255682Smarkmicmp6_read_avail(net_protocol *protocol)
18357416Smarkm{
18457416Smarkm	return B_ERROR;
18557416Smarkm}
18657416Smarkm
18757416Smarkm
18857416Smarkmstruct net_domain *
18955682Smarkmicmp6_get_domain(net_protocol *protocol)
19055682Smarkm{
19155682Smarkm	return protocol->next->module->get_domain(protocol->next);
19255682Smarkm}
19355682Smarkm
19455682Smarkm
19557416Smarkmsize_t
19657416Smarkmicmp6_get_mtu(net_protocol *protocol, const struct sockaddr *address)
19757416Smarkm{
19855682Smarkm	return protocol->next->module->get_mtu(protocol->next, address);
19955682Smarkm}
20057416Smarkm
20155682Smarkm
20255682Smarkmstatic net_domain*
20355682Smarkmget_domain(struct net_buffer* buffer)
204233294Sstas{
20557416Smarkm	net_domain* domain;
20657416Smarkm	if (buffer->interface_address != NULL)
20755682Smarkm		domain = buffer->interface_address->domain;
208233294Sstas	else
20955682Smarkm		domain = sStackModule->get_domain(buffer->source->sa_family);
21057416Smarkm
21157416Smarkm	if (domain == NULL || domain->module == NULL)
21257416Smarkm		return NULL;
21357416Smarkm
21457416Smarkm	return domain;
21557416Smarkm}
21657416Smarkm
21757416Smarkm
21857416Smarkmstatus_t
21955682Smarkmicmp6_receive_data(net_buffer *buffer)
22057416Smarkm{
22157416Smarkm	TRACE(("ICMPv6 received some data, buffer length %" B_PRIu32 "\n",
22255682Smarkm		buffer->size));
22355682Smarkm
22455682Smarkm	net_domain* domain = get_domain(buffer);
22555682Smarkm	if (domain == NULL)
22655682Smarkm		return B_ERROR;
22755682Smarkm
22855682Smarkm	NetBufferHeaderReader<icmp6_hdr> bufferHeader(buffer);
22955682Smarkm	if (bufferHeader.Status() < B_OK)
23057416Smarkm		return bufferHeader.Status();
23155682Smarkm
23255682Smarkm	icmp6_hdr &header = bufferHeader.Data();
23357416Smarkm
23457416Smarkm	TRACE(("  got type %u, code %u, checksum 0x%x\n", header.icmp6_type,
23557416Smarkm			header.icmp6_code, header.icmp6_cksum));
23657416Smarkm
23757416Smarkm	net_address_module_info* addressModule = domain->address_module;
23857416Smarkm
23955682Smarkm	// compute and check the checksum
24057416Smarkm 	if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer,
24155682Smarkm 			IPPROTO_ICMPV6) != 0)
24257416Smarkm 		return B_BAD_DATA;
24357416Smarkm
24457416Smarkm	switch (header.icmp6_type) {
24555682Smarkm		case ICMP6_ECHO_REPLY:
24657416Smarkm			break;
24757416Smarkm
24857416Smarkm		case ICMP6_ECHO_REQUEST:
24957416Smarkm		{
25057416Smarkm			if (buffer->interface_address != NULL) {
25157416Smarkm				// We only reply to echo requests of our local interface; we
25257416Smarkm				// don't reply to broadcast requests
25357416Smarkm				if (!domain->address_module->equal_addresses(
25455682Smarkm						buffer->interface_address->local, buffer->destination))
25555682Smarkm					break;
25657416Smarkm			}
25757416Smarkm
25855682Smarkm			net_buffer *reply = gBufferModule->duplicate(buffer);
25957416Smarkm			if (reply == NULL)
26057416Smarkm				return B_NO_MEMORY;
26155682Smarkm
26257416Smarkm			gBufferModule->swap_addresses(reply);
26357416Smarkm
26457416Smarkm			// There already is an ICMP header, and we'll reuse it
26557416Smarkm			NetBufferHeaderReader<icmp6_hdr> header(reply);
26657416Smarkm
26757416Smarkm			header->icmp6_type = ICMP6_ECHO_REPLY;
26857416Smarkm			header->icmp6_code = 0;
26957416Smarkm			header->icmp6_cksum = 0;
27057416Smarkm
27155682Smarkm			header.Sync();
27255682Smarkm
27357416Smarkm			*ICMP6ChecksumField(reply) = Checksum::PseudoHeader(addressModule,
27457416Smarkm				gBufferModule, buffer, IPPROTO_ICMPV6);
27557416Smarkm
27657416Smarkm			status_t status = domain->module->send_data(NULL, reply);
277178825Sdfr			if (status < B_OK) {
27857416Smarkm				gBufferModule->free(reply);
27957416Smarkm				return status;
28057416Smarkm			}
28157416Smarkm		}
28257416Smarkm
28357416Smarkm		default:
28457416Smarkm			// unrecognized messages go to neighbor discovery protocol handler
28590926Snectar			return sIPv6NDPModule->receive_data(buffer);
28690926Snectar	}
28755682Smarkm
28890926Snectar	gBufferModule->free(buffer);
28990926Snectar	return B_OK;
29090926Snectar}
291103423Snectar
29290926Snectar
293103423Snectarstatus_t
294103423Snectaricmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
29590926Snectar{
29690926Snectar	// TODO: does this look OK?
29790926Snectar	return icmp6_receive_data(buffer);
29890926Snectar}
29990926Snectar
30090926Snectar
30190926Snectarstatus_t
30290926Snectaricmp6_error_received(net_error code, net_buffer* data)
30390926Snectar{
30490926Snectar 	return B_ERROR;
30590926Snectar}
30690926Snectar
30790926Snectar
30890926Snectarstatus_t
30955682Smarkmicmp6_error_reply(net_protocol* protocol, net_buffer* buffer, net_error error,
31055682Smarkm	net_error_data* errorData)
311178825Sdfr{
312178825Sdfr	return B_ERROR;
313178825Sdfr}
314178825Sdfr
315178825Sdfr
31690926Snectar//	#pragma mark -
317178825Sdfr
318178825Sdfr
319178825Sdfrstatic status_t
320178825Sdfricmp6_init()
321178825Sdfr{
322178825Sdfr	sStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6,
323178825Sdfr		"network/protocols/icmp6/v1",
324178825Sdfr		"network/protocols/ipv6/v1",
325178825Sdfr		NULL);
326178825Sdfr
327178825Sdfr	sStackModule->register_domain_receiving_protocol(AF_INET6, IPPROTO_ICMPV6,
328178825Sdfr		"network/protocols/icmp6/v1");
329178825Sdfr
330178825Sdfr	return B_OK;
331178825Sdfr}
332178825Sdfr
333178825Sdfr
334233294Sstasstatic status_t
335233294Sstasicmp6_std_ops(int32 op, ...)
336178825Sdfr{
337233294Sstas	switch (op) {
338178825Sdfr		case B_MODULE_INIT:
339178825Sdfr			return icmp6_init();
340178825Sdfr
341178825Sdfr		case B_MODULE_UNINIT:
342178825Sdfr			return B_OK;
343178825Sdfr
344178825Sdfr		default:
345178825Sdfr			return B_ERROR;
346178825Sdfr	}
347178825Sdfr}
348178825Sdfr
349178825Sdfr
350178825Sdfrnet_protocol_module_info sICMP6Module = {
351178825Sdfr	{
352178825Sdfr		"network/protocols/icmp6/v1",
353178825Sdfr		0,
354178825Sdfr		icmp6_std_ops
355178825Sdfr	},
356178825Sdfr	NET_PROTOCOL_ATOMIC_MESSAGES,
35757416Smarkm
35857416Smarkm	icmp6_init_protocol,
35957416Smarkm	icmp6_uninit_protocol,
36057416Smarkm	icmp6_open,
36157416Smarkm	icmp6_close,
36257416Smarkm	icmp6_free,
363178825Sdfr	icmp6_connect,
36455682Smarkm	icmp6_accept,
36555682Smarkm	icmp6_control,
36655682Smarkm	icmp6_getsockopt,
36790926Snectar	icmp6_setsockopt,
36855682Smarkm	icmp6_bind,
36955682Smarkm	icmp6_unbind,
37055682Smarkm	icmp6_listen,
37155682Smarkm	icmp6_shutdown,
372178825Sdfr	icmp6_send_data,
37355682Smarkm	icmp6_send_routed_data,
37455682Smarkm	icmp6_send_avail,
37555682Smarkm	icmp6_read_data,
37655682Smarkm	icmp6_read_avail,
37755682Smarkm	icmp6_get_domain,
37857416Smarkm	icmp6_get_mtu,
37955682Smarkm	icmp6_receive_data,
38072445Sassar	icmp6_deliver_data,
38172445Sassar	icmp6_error_received,
38272445Sassar	icmp6_error_reply,
38372445Sassar	NULL,		// add_ancillary_data()
38472445Sassar	NULL,		// process_ancillary_data()
38572445Sassar	NULL,		// process_ancillary_data_no_container()
38672445Sassar	NULL,		// send_data_no_buffer()
387178825Sdfr	NULL		// read_data_no_buffer()
38855682Smarkm};
389178825Sdfr
39055682Smarkmmodule_dependency module_dependencies[] = {
39155682Smarkm	{NET_STACK_MODULE_NAME, (module_info **)&sStackModule},
39255682Smarkm	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
39357416Smarkm	{"network/datalink_protocols/ipv6_datagram/ndp/v1",
39455682Smarkm		(module_info **)&sIPv6NDPModule},
39555682Smarkm	{}
39672445Sassar};
39772445Sassar
39855682Smarkmmodule_info *modules[] = {
399178825Sdfr	(module_info *)&sICMP6Module,
400178825Sdfr	NULL
401178825Sdfr};
402178825Sdfr