2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
7 #include <net_datalink.h>
8 #include <net_protocol.h>
10 #include <net_datalink_protocol.h>
11 #include <NetUtilities.h>
12 #include <NetBufferUtilities.h>
14 #include <KernelExport.h>
15 #include <util/list.h>
17 #include <netinet/icmp6.h>
18 #include <netinet/in.h>
23 #include <ipv6_datagram/ndp.h>
28 # define TRACE(x) dprintf x
34 typedef NetBufferField
<uint16
, offsetof(icmp6_hdr
, icmp6_cksum
)> ICMP6ChecksumField
;
37 net_buffer_module_info
*gBufferModule
;
38 static net_stack_module_info
*sStackModule
;
39 static net_ndp_module_info
*sIPv6NDPModule
;
43 icmp6_init_protocol(net_socket
*socket
)
45 net_protocol
*protocol
= new (std::nothrow
) net_protocol
;
54 icmp6_uninit_protocol(net_protocol
*protocol
)
62 icmp6_open(net_protocol
*protocol
)
69 icmp6_close(net_protocol
*protocol
)
76 icmp6_free(net_protocol
*protocol
)
83 icmp6_connect(net_protocol
*protocol
, const struct sockaddr
*address
)
90 icmp6_accept(net_protocol
*protocol
, struct net_socket
**_acceptedSocket
)
97 icmp6_control(net_protocol
*protocol
, int level
, int option
, void *value
,
100 return protocol
->next
->module
->control(protocol
->next
, level
, option
,
106 icmp6_getsockopt(net_protocol
*protocol
, int level
, int option
,
107 void *value
, int *length
)
109 return protocol
->next
->module
->getsockopt(protocol
->next
, level
, option
,
115 icmp6_setsockopt(net_protocol
*protocol
, int level
, int option
,
116 const void *value
, int length
)
118 return protocol
->next
->module
->setsockopt(protocol
->next
, level
, option
,
124 icmp6_bind(net_protocol
*protocol
, const struct sockaddr
*address
)
131 icmp6_unbind(net_protocol
*protocol
, struct sockaddr
*address
)
138 icmp6_listen(net_protocol
*protocol
, int count
)
145 icmp6_shutdown(net_protocol
*protocol
, int direction
)
152 icmp6_send_data(net_protocol
*protocol
, net_buffer
*buffer
)
154 return protocol
->next
->module
->send_data(protocol
->next
, buffer
);
159 icmp6_send_routed_data(net_protocol
*protocol
, struct net_route
*route
,
162 return protocol
->next
->module
->send_routed_data(protocol
->next
, route
, buffer
);
167 icmp6_send_avail(net_protocol
*protocol
)
174 icmp6_read_data(net_protocol
*protocol
, size_t numBytes
, uint32 flags
,
175 net_buffer
**_buffer
)
182 icmp6_read_avail(net_protocol
*protocol
)
189 icmp6_get_domain(net_protocol
*protocol
)
191 return protocol
->next
->module
->get_domain(protocol
->next
);
196 icmp6_get_mtu(net_protocol
*protocol
, const struct sockaddr
*address
)
198 return protocol
->next
->module
->get_mtu(protocol
->next
, address
);
203 get_domain(struct net_buffer
* buffer
)
206 if (buffer
->interface_address
!= NULL
)
207 domain
= buffer
->interface_address
->domain
;
209 domain
= sStackModule
->get_domain(buffer
->source
->sa_family
);
211 if (domain
== NULL
|| domain
->module
== NULL
)
219 icmp6_receive_data(net_buffer
*buffer
)
221 TRACE(("ICMPv6 received some data, buffer length %" B_PRIu32
"\n",
224 net_domain
* domain
= get_domain(buffer
);
228 NetBufferHeaderReader
<icmp6_hdr
> bufferHeader(buffer
);
229 if (bufferHeader
.Status() < B_OK
)
230 return bufferHeader
.Status();
232 icmp6_hdr
&header
= bufferHeader
.Data();
234 TRACE((" got type %u, code %u, checksum 0x%x\n", header
.icmp6_type
,
235 header
.icmp6_code
, header
.icmp6_cksum
));
237 net_address_module_info
* addressModule
= domain
->address_module
;
239 // compute and check the checksum
240 if (Checksum::PseudoHeader(addressModule
, gBufferModule
, buffer
,
241 IPPROTO_ICMPV6
) != 0)
244 switch (header
.icmp6_type
) {
245 case ICMP6_ECHO_REPLY
:
248 case ICMP6_ECHO_REQUEST
:
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
))
258 net_buffer
*reply
= gBufferModule
->duplicate(buffer
);
262 gBufferModule
->swap_addresses(reply
);
264 // There already is an ICMP header, and we'll reuse it
265 NetBufferHeaderReader
<icmp6_hdr
> header(reply
);
267 header
->icmp6_type
= ICMP6_ECHO_REPLY
;
268 header
->icmp6_code
= 0;
269 header
->icmp6_cksum
= 0;
273 *ICMP6ChecksumField(reply
) = Checksum::PseudoHeader(addressModule
,
274 gBufferModule
, buffer
, IPPROTO_ICMPV6
);
276 status_t status
= domain
->module
->send_data(NULL
, reply
);
278 gBufferModule
->free(reply
);
284 // unrecognized messages go to neighbor discovery protocol handler
285 return sIPv6NDPModule
->receive_data(buffer
);
288 gBufferModule
->free(buffer
);
294 icmp6_deliver_data(net_protocol
*protocol
, net_buffer
*buffer
)
296 // TODO: does this look OK?
297 return icmp6_receive_data(buffer
);
302 icmp6_error_received(net_error code
, net_buffer
* data
)
309 icmp6_error_reply(net_protocol
* protocol
, net_buffer
* buffer
, net_error error
,
310 net_error_data
* errorData
)
322 sStackModule
->register_domain_protocols(AF_INET6
, SOCK_DGRAM
, IPPROTO_ICMPV6
,
323 "network/protocols/icmp6/v1",
324 "network/protocols/ipv6/v1",
327 sStackModule
->register_domain_receiving_protocol(AF_INET6
, IPPROTO_ICMPV6
,
328 "network/protocols/icmp6/v1");
335 icmp6_std_ops(int32 op
, ...)
341 case B_MODULE_UNINIT
:
350 net_protocol_module_info sICMP6Module
= {
352 "network/protocols/icmp6/v1",
356 NET_PROTOCOL_ATOMIC_MESSAGES
,
359 icmp6_uninit_protocol
,
373 icmp6_send_routed_data
,
381 icmp6_error_received
,
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()
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
},
398 module_info
*modules
[] = {
399 (module_info
*)&sICMP6Module
,