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 34typedef NetBufferField<uint16, offsetof(icmp6_hdr, icmp6_cksum)> ICMP6ChecksumField; 35 36 37net_buffer_module_info *gBufferModule; 38static net_stack_module_info *sStackModule; 39static net_ndp_module_info *sIPv6NDPModule; 40 41 42net_protocol * 43icmp6_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 53status_t 54icmp6_uninit_protocol(net_protocol *protocol) 55{ 56 delete protocol; 57 return B_OK; 58} 59 60 61status_t 62icmp6_open(net_protocol *protocol) 63{ 64 return B_OK; 65} 66 67 68status_t 69icmp6_close(net_protocol *protocol) 70{ 71 return B_OK; 72} 73 74 75status_t 76icmp6_free(net_protocol *protocol) 77{ 78 return B_OK; 79} 80 81 82status_t 83icmp6_connect(net_protocol *protocol, const struct sockaddr *address) 84{ 85 return B_ERROR; 86} 87 88 89status_t 90icmp6_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 91{ 92 return EOPNOTSUPP; 93} 94 95 96status_t 97icmp6_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 105status_t 106icmp6_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 114status_t 115icmp6_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 123status_t 124icmp6_bind(net_protocol *protocol, const struct sockaddr *address) 125{ 126 return B_ERROR; 127} 128 129 130status_t 131icmp6_unbind(net_protocol *protocol, struct sockaddr *address) 132{ 133 return B_ERROR; 134} 135 136 137status_t 138icmp6_listen(net_protocol *protocol, int count) 139{ 140 return EOPNOTSUPP; 141} 142 143 144status_t 145icmp6_shutdown(net_protocol *protocol, int direction) 146{ 147 return EOPNOTSUPP; 148} 149 150 151status_t 152icmp6_send_data(net_protocol *protocol, net_buffer *buffer) 153{ 154 return protocol->next->module->send_data(protocol->next, buffer); 155} 156 157 158status_t 159icmp6_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 166ssize_t 167icmp6_send_avail(net_protocol *protocol) 168{ 169 return B_ERROR; 170} 171 172 173status_t 174icmp6_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 175 net_buffer **_buffer) 176{ 177 return B_ERROR; 178} 179 180 181ssize_t 182icmp6_read_avail(net_protocol *protocol) 183{ 184 return B_ERROR; 185} 186 187 188struct net_domain * 189icmp6_get_domain(net_protocol *protocol) 190{ 191 return protocol->next->module->get_domain(protocol->next); 192} 193 194 195size_t 196icmp6_get_mtu(net_protocol *protocol, const struct sockaddr *address) 197{ 198 return protocol->next->module->get_mtu(protocol->next, address); 199} 200 201 202static net_domain* 203get_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 218status_t 219icmp6_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 293status_t 294icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer) 295{ 296 // TODO: does this look OK? 297 return icmp6_receive_data(buffer); 298} 299 300 301status_t 302icmp6_error_received(net_error code, net_buffer* data) 303{ 304 return B_ERROR; 305} 306 307 308status_t 309icmp6_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 319static status_t 320icmp6_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 334static status_t 335icmp6_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 350net_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 390module_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 398module_info *modules[] = { 399 (module_info *)&sICMP6Module, 400 NULL 401}; 402