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