1/* 2 * Copyright 2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Atis Elsts, the.kfx@gmail.com 7 */ 8 9 10#include <net_datalink.h> 11#include <net_datalink_protocol.h> 12#include <net_device.h> 13#include <net_stack.h> 14#include <net_protocol.h> 15#include <NetBufferUtilities.h> 16 17#include <generic_syscall.h> 18#include <util/atomic.h> 19#include <util/AutoLock.h> 20#include <util/DoublyLinkedList.h> 21#include <util/OpenHashTable.h> 22#include <KernelExport.h> 23 24#include <netinet/in.h> 25#include <netinet6/in6.h> 26#include <netinet/icmp6.h> 27#include <net/ethernet.h> 28#include <net/if.h> 29#include <net/if_types.h> 30#include <net/if_dl.h> 31#include <sys/sockio.h> 32#include <new> 33 34#include <ipv6/jenkins.h> 35#include <ipv6/ipv6_address.h> 36#include "ndp.h" 37 38 39//#define TRACE_NDP 40#ifdef TRACE_NDP 41# define TRACE(x) dprintf x 42#else 43# define TRACE(x) ; 44#endif 45 46 47struct ipv6_datalink_protocol : net_datalink_protocol { 48 sockaddr_dl hardware_address; 49 in6_addr local_address; 50}; 51 52 53static void ndp_timer(struct net_timer* timer, void* data); 54 55 56net_buffer_module_info* gBufferModule; 57static net_stack_module_info* sStackModule; 58static net_datalink_module_info* sDatalinkModule; 59static net_protocol_module_info* sIPv6Module; 60static net_protocol* sIPv6Protocol; 61static mutex sCacheLock; 62static const net_buffer* kDeletedBuffer = (net_buffer*)~0; 63 64// needed for IN6_IS_ADDR_UNSPECIFIED() macro 65const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 66 67// #pragma mark - 68 69 70struct neighbor_discovery_header { 71 uint8 icmp6_type; 72 uint8 icmp6_code; 73 uint16 icmp6_checksum; 74 uint32 flags; 75 in6_addr target_address; 76 77 // This part is specific for Ethernet; 78 // also, theoretically there could be more than one option. 79 uint8 option_type; 80 uint8 option_length; 81 uint8 link_address[ETHER_ADDRESS_LENGTH]; 82} _PACKED; 83 84struct router_advertisement_header { 85 uint8 icmp6_type; 86 uint8 icmp6_code; 87 uint16 icmp6_checksum; 88 uint8 hop_limit; 89 uint8 flags; 90 uint16 router_lifetime; 91 uint32 reachable_time; 92 uint32 retransmit_timer; 93 uint8 options[0]; 94} _PACKED; 95 96 97struct ndp_entry { 98 ndp_entry* next; 99 in6_addr protocol_address; 100 sockaddr_dl hardware_address; 101 uint32 flags; 102 net_buffer* request_buffer; 103 net_timer timer; 104 uint32 timer_state; 105 bigtime_t timestamp; 106 net_datalink_protocol* protocol; 107 108 typedef DoublyLinkedListCLink<net_buffer> NetBufferLink; 109 typedef DoublyLinkedList<net_buffer, NetBufferLink> BufferList; 110 111 BufferList queue; 112 113 static ndp_entry* Lookup(const in6_addr& protocolAddress); 114 static ndp_entry* Add(const in6_addr& protocolAddress, 115 sockaddr_dl* hardwareAddress, uint32 flags); 116 117 ~ndp_entry(); 118 119 void ClearQueue(); 120 void MarkFailed(); 121 void MarkValid(); 122 void ScheduleRemoval(); 123}; 124 125 126struct ndpHash { 127 typedef in6_addr KeyType; 128 typedef ndp_entry ValueType; 129 130 size_t HashKey(in6_addr key) const 131 { 132 return jenkins_hashword((const uint32*)&(key), 133 sizeof(in6_addr) / sizeof(uint32), 0); 134 } 135 136 size_t Hash(ndp_entry* value) const 137 { 138 return HashKey(value->protocol_address); 139 } 140 141 bool Compare(in6_addr key, ndp_entry* value) const 142 { 143 return value->protocol_address == key; 144 } 145 146 ndp_entry*& GetLink(ndp_entry* value) const 147 { 148 return value->next; 149 } 150}; 151 152 153typedef BOpenHashTable<ndpHash> AddressCache; 154static AddressCache* sCache; 155 156 157#define NDP_FLAG_LOCAL 0x01 158#define NDP_FLAG_REJECT 0x02 159#define NDP_FLAG_PERMANENT 0x04 160#define NDP_FLAG_PUBLISH 0x08 161#define NDP_FLAG_VALID 0x10 162 163#define NDP_FLAG_REMOVED 0x00010000 164#define NDP_PUBLIC_FLAG_MASK 0x0000ffff 165 166#define NDP_NO_STATE 0 167#define NDP_STATE_REQUEST 1 168#define NDP_STATE_LAST_REQUEST 5 169#define NDP_STATE_REQUEST_FAILED 6 170#define NDP_STATE_REMOVE_FAILED 7 171#define NDP_STATE_STALE 8 172 173#define NDP_STALE_TIMEOUT 30 * 60000000LL // 30 minutes 174#define NDP_REJECT_TIMEOUT 20000000LL // 20 seconds 175#define NDP_REQUEST_TIMEOUT 1000000LL // 1 second 176 177 178// #pragma mark - 179 180 181static void 182ipv6_to_ether_multicast(sockaddr_dl* destination, const sockaddr_in6* source) 183{ 184 // To send an IPv6 multicast packet over Ethernet, 185 // take the last 32 bits of the destination IPv6 address, 186 // prepend 33-33- and use that as the destination Ethernet address. 187 188 destination->sdl_len = sizeof(sockaddr_dl); 189 destination->sdl_family = AF_LINK; 190 destination->sdl_index = 0; 191 destination->sdl_type = IFT_ETHER; 192 destination->sdl_e_type = htons(ETHER_TYPE_IPV6); 193 destination->sdl_nlen = destination->sdl_slen = 0; 194 destination->sdl_alen = ETHER_ADDRESS_LENGTH; 195 196 destination->sdl_data[0] = 0x33; 197 destination->sdl_data[1] = 0x33; 198 memcpy(&destination->sdl_data[2], &source->sin6_addr.s6_addr[12], 4); 199} 200 201 202static inline sockaddr* 203ipv6_to_sockaddr(sockaddr_in6* target, const in6_addr& address) 204{ 205 target->sin6_family = AF_INET6; 206 target->sin6_len = sizeof(sockaddr_in6); 207 target->sin6_port = 0; 208 target->sin6_flowinfo = 0; 209 target->sin6_scope_id = 0; 210 memcpy(target->sin6_addr.s6_addr, address.s6_addr, sizeof(in6_addr)); 211 return (sockaddr*)target; 212} 213 214 215static inline sockaddr* 216ipv6_to_solicited_multicast(sockaddr_in6* target, const in6_addr& address) 217{ 218 // The solicited-node multicast address for a given unicast address 219 // is constructed by taking the last three octets of the unicast address 220 // and prepending FF02::1:FF00:0000/104. 221 222 target->sin6_family = AF_INET6; 223 target->sin6_len = sizeof(sockaddr_in6); 224 target->sin6_port = 0; 225 target->sin6_flowinfo = 0; 226 target->sin6_scope_id = 0; 227 228 uint8* targetIPv6 = target->sin6_addr.s6_addr; 229 memset(targetIPv6, 0, sizeof(in6_addr)); 230 targetIPv6[0] = 0xff; 231 targetIPv6[1] = 0x02; 232 targetIPv6[11] = 0x01; 233 targetIPv6[12] = 0xff; 234 memcpy(&targetIPv6[13], &address.s6_addr[13], 3); 235 236 return (sockaddr*)target; 237} 238 239 240// #pragma mark - 241 242 243static net_buffer* 244get_request_buffer(ndp_entry* entry) 245{ 246 net_buffer* buffer = entry->request_buffer; 247 if (buffer == NULL || buffer == kDeletedBuffer) 248 return NULL; 249 250 buffer = atomic_pointer_test_and_set(&entry->request_buffer, 251 (net_buffer*)NULL, buffer); 252 if (buffer == kDeletedBuffer) 253 return NULL; 254 255 return buffer; 256} 257 258 259static void 260put_request_buffer(ndp_entry* entry, net_buffer* buffer) 261{ 262 net_buffer* requestBuffer = atomic_pointer_test_and_set( 263 &entry->request_buffer, buffer, (net_buffer*)NULL); 264 if (requestBuffer != NULL) { 265 // someone else took over ownership of the request buffer 266 gBufferModule->free(buffer); 267 } 268} 269 270 271static void 272delete_request_buffer(ndp_entry* entry) 273{ 274 net_buffer* buffer = atomic_pointer_get_and_set(&entry->request_buffer, 275 kDeletedBuffer); 276 if (buffer != NULL && buffer != kDeletedBuffer) 277 gBufferModule->free(buffer); 278} 279 280 281ndp_entry* 282ndp_entry::Lookup(const in6_addr& address) 283{ 284 return sCache->Lookup(address); 285} 286 287 288ndp_entry* 289ndp_entry::Add(const in6_addr& protocolAddress, sockaddr_dl* hardwareAddress, 290 uint32 flags) 291{ 292 ASSERT_LOCKED_MUTEX(&sCacheLock); 293 294 ndp_entry* entry = new (std::nothrow) ndp_entry; 295 if (entry == NULL) 296 return NULL; 297 298 entry->protocol_address = protocolAddress; 299 entry->flags = flags; 300 entry->timestamp = system_time(); 301 entry->protocol = NULL; 302 entry->request_buffer = NULL; 303 entry->timer_state = NDP_NO_STATE; 304 sStackModule->init_timer(&entry->timer, ndp_timer, entry); 305 306 if (hardwareAddress != NULL) { 307 // this entry is already resolved 308 entry->hardware_address = *hardwareAddress; 309 entry->hardware_address.sdl_e_type = htons(ETHER_TYPE_IPV6); 310 } else { 311 // this entry still needs to be resolved 312 entry->hardware_address.sdl_alen = 0; 313 } 314 if (entry->hardware_address.sdl_len != sizeof(sockaddr_dl)) { 315 // explicitly set correct length in case our caller hasn't... 316 entry->hardware_address.sdl_len = sizeof(sockaddr_dl); 317 } 318 319 if (sCache->Insert(entry) != B_OK) { 320 // We can delete the entry here with the sCacheLock held, since it's 321 // guaranteed there are no timers pending. 322 delete entry; 323 return NULL; 324 } 325 326 return entry; 327} 328 329 330ndp_entry::~ndp_entry() 331{ 332 // make sure there is no active timer left for us 333 sStackModule->cancel_timer(&timer); 334 sStackModule->wait_for_timer(&timer); 335 336 ClearQueue(); 337} 338 339 340void 341ndp_entry::ClearQueue() 342{ 343 BufferList::Iterator iterator = queue.GetIterator(); 344 while (iterator.HasNext()) { 345 net_buffer* buffer = iterator.Next(); 346 iterator.Remove(); 347 gBufferModule->free(buffer); 348 } 349} 350 351 352void 353ndp_entry::MarkFailed() 354{ 355 TRACE(("NDP entry %p Marked as FAILED\n", this)); 356 357 flags = (flags & ~NDP_FLAG_VALID) | NDP_FLAG_REJECT; 358 ClearQueue(); 359} 360 361 362void 363ndp_entry::MarkValid() 364{ 365 TRACE(("NDP entry %p Marked as VALID\n", this)); 366 367 flags = (flags & ~NDP_FLAG_REJECT) | NDP_FLAG_VALID; 368 369 BufferList::Iterator iterator = queue.GetIterator(); 370 while (iterator.HasNext()) { 371 net_buffer* buffer = iterator.Next(); 372 iterator.Remove(); 373 374 TRACE((" NDP Dequeing packet %p...\n", buffer)); 375 376 memcpy(buffer->destination, &hardware_address, 377 hardware_address.sdl_len); 378 protocol->next->module->send_data(protocol->next, buffer); 379 } 380} 381 382 383void 384ndp_entry::ScheduleRemoval() 385{ 386 // schedule a timer to remove this entry 387 timer_state = NDP_STATE_REMOVE_FAILED; 388 sStackModule->set_timer(&timer, 0); 389} 390 391 392// #pragma mark - 393 394 395static status_t 396ndp_init() 397{ 398 sIPv6Protocol = sIPv6Module->init_protocol(NULL); 399 if (sIPv6Protocol == NULL) 400 return B_NO_MEMORY; 401 sIPv6Protocol->module = sIPv6Module; 402 sIPv6Protocol->socket = NULL; 403 sIPv6Protocol->next = NULL; 404 405 int value = 255; 406 sIPv6Module->setsockopt(sIPv6Protocol, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 407 &value, sizeof(value)); 408 sIPv6Module->setsockopt(sIPv6Protocol, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 409 &value, sizeof(value)); 410 411 mutex_init(&sCacheLock, "ndp cache"); 412 413 sCache = new(std::nothrow) AddressCache(); 414 if (sCache == NULL || sCache->Init(64) != B_OK) { 415 mutex_destroy(&sCacheLock); 416 return B_NO_MEMORY; 417 } 418 419 return B_OK; 420} 421 422 423static status_t 424ndp_uninit() 425{ 426 if (sIPv6Protocol) 427 sIPv6Module->uninit_protocol(sIPv6Protocol); 428 429 return B_OK; 430} 431 432 433// #pragma mark - 434 435 436/*! Updates the entry determined by \a protocolAddress with the specified 437 \a hardwareAddress. 438 If such an entry does not exist yet, a new entry is added. If you try 439 to update a local existing entry but didn't ask for it (by setting 440 \a flags to NDP_FLAG_LOCAL), an error is returned. 441 442 This function does not lock the cache - you have to do it yourself 443 before calling it. 444*/ 445status_t 446ndp_update_entry(const in6_addr& protocolAddress, sockaddr_dl* hardwareAddress, 447 uint32 flags, ndp_entry** _entry = NULL) 448{ 449 ASSERT_LOCKED_MUTEX(&sCacheLock); 450 451 ndp_entry* entry = ndp_entry::Lookup(protocolAddress); 452 if (entry != NULL) { 453 // We disallow updating of entries that had been resolved before, 454 // but to a different address (only for those that belong to a 455 // specific address - redefining INADDR_ANY is always allowed). 456 // Right now, you have to manually purge the NDP entries (or wait some 457 // time) to let us switch to the new address. 458 if (!IN6_IS_ADDR_UNSPECIFIED(&protocolAddress) 459 && entry->hardware_address.sdl_alen != 0 460 && memcmp(LLADDR(&entry->hardware_address), 461 LLADDR(hardwareAddress), ETHER_ADDRESS_LENGTH)) { 462 // TODO: also printf the address 463 dprintf("NDP host updated with different hardware address " 464 "%02x:%02x:%02x:%02x:%02x:%02x.\n", 465 hardwareAddress->sdl_data[0], hardwareAddress->sdl_data[1], 466 hardwareAddress->sdl_data[2], hardwareAddress->sdl_data[3], 467 hardwareAddress->sdl_data[4], hardwareAddress->sdl_data[5]); 468 return B_ERROR; 469 } 470 471 entry->hardware_address = *hardwareAddress; 472 entry->timestamp = system_time(); 473 } else { 474 entry = ndp_entry::Add(protocolAddress, hardwareAddress, flags); 475 if (entry == NULL) 476 return B_NO_MEMORY; 477 } 478 479 delete_request_buffer(entry); 480 481 if ((entry->flags & NDP_FLAG_PERMANENT) == 0) { 482 // (re)start the stale timer 483 entry->timer_state = NDP_STATE_STALE; 484 sStackModule->set_timer(&entry->timer, NDP_STALE_TIMEOUT); 485 } 486 487 if ((entry->flags & NDP_FLAG_REJECT) != 0) 488 entry->MarkFailed(); 489 else 490 entry->MarkValid(); 491 492 if (_entry) 493 *_entry = entry; 494 495 return B_OK; 496} 497 498 499static void 500ndp_remove_local_entry(ipv6_datalink_protocol* protocol, const sockaddr* local, 501 bool updateLocalAddress) 502{ 503 in6_addr inetAddress; 504 505 if (local == NULL) { 506 // interface has not yet been set 507 memset(&inetAddress, 0, sizeof(in6_addr)); 508 } else { 509 memcpy(&inetAddress, &((sockaddr_in6*)local)->sin6_addr, 510 sizeof(in6_addr)); 511 512 // leave the NS multicast address 513 sockaddr_in6 multicast; 514 ipv6_to_solicited_multicast(&multicast, inetAddress); 515 516 struct ipv6_mreq mreq; 517 memcpy(&mreq.ipv6mr_multiaddr, &multicast.sin6_addr, sizeof(in6_addr)); 518 mreq.ipv6mr_interface = protocol->interface->index; 519 520 if (sIPv6Protocol != NULL) { 521 sIPv6Module->setsockopt(sIPv6Protocol, IPPROTO_IPV6, 522 IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)); 523 } 524 } 525 526 // TRACE(("%s(): address %s\n", __FUNCTION__, inet6_to_string(inetAddress))); 527 528 MutexLocker locker(sCacheLock); 529 530 ndp_entry* entry = ndp_entry::Lookup(inetAddress); 531 if (entry != NULL) { 532 sCache->Remove(entry); 533 entry->flags |= NDP_FLAG_REMOVED; 534 } 535 536 if (updateLocalAddress && protocol->local_address == inetAddress) { 537 // find new local sender address 538 memset(&protocol->local_address, 0, sizeof(in6_addr)); 539 540 net_interface_address* address = NULL; 541 while (sDatalinkModule->get_next_interface_address(protocol->interface, 542 &address)) { 543 if (address->local == NULL || address->local->sa_family != AF_INET6) 544 continue; 545 546 memcpy(&protocol->local_address, 547 &((sockaddr_in6*)address->local)->sin6_addr, sizeof(in6_addr)); 548 } 549 } 550 551 locker.Unlock(); 552 delete entry; 553} 554 555 556/*! Removes all entries belonging to the local interface of the \a procotol 557 given. 558*/ 559static void 560ndp_remove_local(ipv6_datalink_protocol* protocol) 561{ 562 net_interface_address* address = NULL; 563 while (sDatalinkModule->get_next_interface_address(protocol->interface, 564 &address)) { 565 if (address->local == NULL || address->local->sa_family != AF_INET6) 566 continue; 567 568 ndp_remove_local_entry(protocol, address->local, false); 569 } 570} 571 572 573static status_t 574ndp_set_local_entry(ipv6_datalink_protocol* protocol, const sockaddr* local) 575{ 576 MutexLocker locker(sCacheLock); 577 578 net_interface* interface = protocol->interface; 579 in6_addr inetAddress; 580 581 if (local == NULL) { 582 // interface has not yet been set 583 memset(&inetAddress, 0, sizeof(in6_addr)); 584 } else { 585 memcpy(&inetAddress, 586 &((sockaddr_in6*)local)->sin6_addr, 587 sizeof(in6_addr)); 588 589 // join multicast address for listening to NS packets 590 sockaddr_in6 multicast; 591 ipv6_to_solicited_multicast(&multicast, inetAddress); 592 593 struct ipv6_mreq mreq; 594 memcpy(&mreq.ipv6mr_multiaddr, &multicast.sin6_addr, sizeof(in6_addr)); 595 mreq.ipv6mr_interface = protocol->interface->index; 596 597 if (sIPv6Protocol != NULL) { 598 sIPv6Module->setsockopt(sIPv6Protocol, IPPROTO_IPV6, 599 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)); 600 } 601 } 602 603 // TRACE(("%s(): address %s\n", __FUNCTION__, inet6_to_string(inetAddress))); 604 605 if (IN6_IS_ADDR_UNSPECIFIED(&protocol->local_address)) 606 memcpy(&protocol->local_address, &inetAddress, sizeof(in6_addr)); 607 608 sockaddr_dl address; 609 address.sdl_len = sizeof(sockaddr_dl); 610 address.sdl_family = AF_LINK; 611 address.sdl_type = IFT_ETHER; 612 address.sdl_e_type = htons(ETHER_TYPE_IPV6); 613 address.sdl_nlen = 0; 614 address.sdl_slen = 0; 615 address.sdl_alen = interface->device->address.length; 616 memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen); 617 618 memcpy(&protocol->hardware_address, &address, sizeof(sockaddr_dl)); 619 // cache the address in our protocol 620 621 ndp_entry* entry; 622 status_t status = ndp_update_entry(inetAddress, &address, 623 NDP_FLAG_LOCAL | NDP_FLAG_PERMANENT, &entry); 624 if (status == B_OK) 625 entry->protocol = protocol; 626 627 return status; 628} 629 630 631/*! Creates permanent local entries for all addresses of the interface belonging 632 to this protocol. 633 Returns an error if no entry could be added. 634*/ 635static status_t 636ndp_update_local(ipv6_datalink_protocol* protocol) 637{ 638 memset(&protocol->local_address, 0, sizeof(in6_addr)); 639 640 ssize_t count = 0; 641 642 net_interface_address* address = NULL; 643 while (sDatalinkModule->get_next_interface_address(protocol->interface, 644 &address)) { 645 if (address->local == NULL || address->local->sa_family != AF_INET6) 646 continue; 647 648 if (ndp_set_local_entry(protocol, address->local) == B_OK) { 649 count++; 650 } 651 } 652 653 if (count == 0) 654 return ndp_set_local_entry(protocol, NULL); 655 656 return B_OK; 657} 658 659 660static status_t 661ndp_receive_solicitation(net_buffer* buffer, bool* reuseBuffer) 662{ 663 *reuseBuffer = false; 664 665 NetBufferHeaderReader<neighbor_discovery_header> bufferHeader(buffer); 666 if (bufferHeader.Status() < B_OK) 667 return bufferHeader.Status(); 668 669 neighbor_discovery_header& header = bufferHeader.Data(); 670 if (header.option_type != ND_OPT_SOURCE_LINKADDR 671 || header.option_length != 1) 672 return B_OK; 673 674 { 675 MutexLocker locker(sCacheLock); 676 677 // remember the address of the sender as we might need it later 678 sockaddr_dl hardwareAddress; 679 hardwareAddress.sdl_len = sizeof(sockaddr_dl); 680 hardwareAddress.sdl_family = AF_LINK; 681 hardwareAddress.sdl_index = 0; 682 hardwareAddress.sdl_type = IFT_ETHER; 683 hardwareAddress.sdl_e_type = htons(ETHER_TYPE_IPV6); 684 hardwareAddress.sdl_nlen = hardwareAddress.sdl_slen = 0; 685 hardwareAddress.sdl_alen = ETHER_ADDRESS_LENGTH; 686 memcpy(LLADDR(&hardwareAddress), header.link_address, 687 ETHER_ADDRESS_LENGTH); 688 689 ndp_update_entry(header.target_address, &hardwareAddress, 0); 690 691 // check if this request is for us 692 693 ndp_entry* entry = ndp_entry::Lookup(header.target_address); 694 if (entry == NULL 695 || (entry->flags & (NDP_FLAG_LOCAL | NDP_FLAG_PUBLISH)) == 0) { 696 // We're not the one to answer this request 697 // TODO: instead of letting the other's request time-out, can we 698 // reply failure somehow? 699 TRACE((" not for us\n")); 700 return B_ERROR; 701 } 702 703 // send a reply (by reusing the buffer we got) 704 gBufferModule->trim(buffer, sizeof(neighbor_discovery_header)); 705 706 header.icmp6_type = ND_NEIGHBOR_ADVERT; 707 header.icmp6_code = 0; 708 header.icmp6_checksum = 0; 709 header.flags = ND_NA_FLAG_SOLICITED; 710 header.option_type = ND_OPT_TARGET_LINKADDR; 711 memcpy(&header.link_address, LLADDR(&entry->hardware_address), 712 ETHER_ADDRESS_LENGTH); 713 bufferHeader.Sync(); 714 } 715 716 // fix source and destination address 717 sockaddr_in6* source = (sockaddr_in6*)buffer->source; 718 sockaddr_in6* destination = (sockaddr_in6*)buffer->destination; 719 memcpy(&destination->sin6_addr, &source->sin6_addr, sizeof(in6_addr)); 720 memcpy(&source->sin6_addr, &header.target_address, sizeof(in6_addr)); 721 722 buffer->flags = 0; 723 // make sure this won't be a broadcast message 724 725 if (sIPv6Protocol == NULL) 726 return B_ERROR; 727 728 *reuseBuffer = true; 729 730 // send the ICMPv6 packet out 731 TRACE(("Sending Neighbor Advertisement\n")); 732 return sIPv6Module->send_data(sIPv6Protocol, buffer); 733} 734 735 736static void 737ndp_receive_advertisement(net_buffer* buffer) 738{ 739 // TODO: also process unsolicited advertisments? 740 if ((buffer->flags & MSG_MCAST) != 0) 741 return; 742 743 NetBufferHeaderReader<neighbor_discovery_header> bufferHeader(buffer); 744 if (bufferHeader.Status() < B_OK) 745 return; 746 747 neighbor_discovery_header& header = bufferHeader.Data(); 748 if (header.option_type != ND_OPT_TARGET_LINKADDR 749 || header.option_length != 1) { 750 return; 751 } 752 753 sockaddr_dl hardwareAddress; 754 hardwareAddress.sdl_len = sizeof(sockaddr_dl); 755 hardwareAddress.sdl_family = AF_LINK; 756 hardwareAddress.sdl_index = 0; 757 hardwareAddress.sdl_type = IFT_ETHER; 758 hardwareAddress.sdl_e_type = htons(ETHER_TYPE_IPV6); 759 hardwareAddress.sdl_nlen = hardwareAddress.sdl_slen = 0; 760 hardwareAddress.sdl_alen = ETHER_ADDRESS_LENGTH; 761 memcpy(LLADDR(&hardwareAddress), header.link_address, ETHER_ADDRESS_LENGTH); 762 763 MutexLocker locker(sCacheLock); 764 // TODO: take in account ND_NA_FLAGs 765 ndp_update_entry(header.target_address, &hardwareAddress, 0); 766} 767 768 769static void 770ndp_receive_router_advertisement(net_buffer* buffer) 771{ 772 NetBufferHeaderReader<router_advertisement_header> bufferHeader(buffer); 773 if (bufferHeader.Status() < B_OK) 774 return; 775 776 // TODO: check for validity 777 778 // TODO: parse the options 779} 780 781 782static status_t 783ndp_receive_data(net_buffer* buffer) 784{ 785 TRACE("ndp_receive_data\n"); 786 787 NetBufferHeaderReader<icmp6_hdr> icmp6Header(buffer); 788 if (icmp6Header.Status() < B_OK) 789 return icmp6Header.Status(); 790 791 bool reuseBuffer = false; 792 793 switch (icmp6Header->icmp6_type) { 794 case ND_NEIGHBOR_SOLICIT: 795 TRACE((" received Neighbor Solicitation\n")); 796 ndp_receive_solicitation(buffer, &reuseBuffer); 797 break; 798 799 case ND_NEIGHBOR_ADVERT: 800 TRACE((" received Neighbor Advertisement\n")); 801 ndp_receive_advertisement(buffer); 802 break; 803 804 case ND_ROUTER_ADVERT: 805 TRACE((" received Router Advertisement\n")); 806 ndp_receive_router_advertisement(buffer); 807 break; 808 } 809 810 if (reuseBuffer == false) 811 gBufferModule->free(buffer); 812 return B_OK; 813} 814 815 816static void 817ndp_timer(struct net_timer* timer, void* data) 818{ 819 ndp_entry* entry = (ndp_entry*)data; 820 TRACE(("NDP timer %" B_PRId32 ", entry %p!\n", entry->timer_state, entry)); 821 822 switch (entry->timer_state) { 823 case NDP_NO_STATE: 824 // who are you kidding? 825 break; 826 827 case NDP_STATE_REQUEST_FAILED: 828 // Requesting the NDP entry failed, we keep it around for a while, 829 // though, so that we won't try to request the same address again 830 // too soon. 831 TRACE((" requesting NDP entry %p failed!\n", entry)); 832 entry->timer_state = NDP_STATE_REMOVE_FAILED; 833 entry->MarkFailed(); 834 sStackModule->set_timer(&entry->timer, NDP_REJECT_TIMEOUT); 835 break; 836 837 case NDP_STATE_REMOVE_FAILED: 838 case NDP_STATE_STALE: 839 // the entry has aged so much that we're going to remove it 840 TRACE((" remove NDP entry %p!\n", entry)); 841 842 mutex_lock(&sCacheLock); 843 if ((entry->flags & NDP_FLAG_REMOVED) != 0) { 844 // The entry has already been removed, and is about to be deleted 845 mutex_unlock(&sCacheLock); 846 break; 847 } 848 849 sCache->Remove(entry); 850 mutex_unlock(&sCacheLock); 851 852 delete entry; 853 break; 854 855 default: 856 { 857 if (entry->timer_state > NDP_STATE_LAST_REQUEST) 858 break; 859 860 TRACE((" send request for NDP entry %p!\n", entry)); 861 862 net_buffer* request = get_request_buffer(entry); 863 if (request == NULL) 864 break; 865 866 if (entry->timer_state < NDP_STATE_LAST_REQUEST) { 867 // we'll still need our buffer, so in order to prevent it being 868 // freed by a successful send, we need to clone it 869 net_buffer* clone = gBufferModule->clone(request, true); 870 if (clone == NULL) { 871 // cloning failed - that means we won't be able to send as 872 // many requests as originally planned 873 entry->timer_state = NDP_STATE_LAST_REQUEST; 874 } else { 875 put_request_buffer(entry, request); 876 request = clone; 877 } 878 } 879 880 if (sIPv6Protocol == NULL) 881 break; 882 883 // we're trying to resolve the address, so keep sending requests 884 status_t status = sIPv6Module->send_data(sIPv6Protocol, request); 885 if (status < B_OK) 886 gBufferModule->free(request); 887 888 entry->timer_state++; 889 sStackModule->set_timer(&entry->timer, NDP_REQUEST_TIMEOUT); 890 break; 891 } 892 } 893} 894 895 896static status_t 897ndp_start_resolve(ipv6_datalink_protocol* protocol, const in6_addr& address, 898 ndp_entry** _entry) 899{ 900 ASSERT_LOCKED_MUTEX(&sCacheLock); 901 902 // create an unresolved entry as a placeholder 903 ndp_entry* entry = ndp_entry::Add(address, NULL, 0); 904 if (entry == NULL) 905 return B_NO_MEMORY; 906 907 // prepare NDP request 908 909 net_buffer* buffer = entry->request_buffer = gBufferModule->create(256); 910 if (entry->request_buffer == NULL) { 911 entry->ScheduleRemoval(); 912 return B_NO_MEMORY; 913 } 914 915 NetBufferPrepend<neighbor_discovery_header> header(buffer); 916 status_t status = header.Status(); 917 if (status < B_OK) { 918 entry->ScheduleRemoval(); 919 return status; 920 } 921 922 net_interface* interface = protocol->interface; 923 net_device* device = interface->device; 924 925 // prepare source and target addresses 926 927 sockaddr_in6* source = (sockaddr_in6*)buffer->source; 928 ipv6_to_sockaddr(source, protocol->local_address); 929 // protocol->local_address 930 931 sockaddr_in6* destination = (sockaddr_in6*)buffer->destination; 932 ipv6_to_solicited_multicast(destination, address); 933 934 buffer->protocol = IPPROTO_ICMPV6; 935 936 // prepare Neighbor Solicitation header 937 938 header->icmp6_type = ND_NEIGHBOR_SOLICIT; 939 header->icmp6_code = 0; 940 header->icmp6_checksum = 0; 941 header->flags = 0; 942 memcpy(&header->target_address, &address, sizeof(in6_addr)); 943 header->option_type = ND_OPT_SOURCE_LINKADDR; 944 header->option_length = (sizeof(nd_opt_hdr) + ETHER_ADDRESS_LENGTH) >> 3; 945 memcpy(&header->link_address, device->address.data, ETHER_ADDRESS_LENGTH); 946 header.Sync(); 947 948 if (sIPv6Protocol == NULL) { 949 entry->ScheduleRemoval(); 950 return B_NO_MEMORY; 951 } 952 953 // this does not work, because multicast for now is only looped back! 954#if FIXME 955 // hack: set to use the correct interface by setting socket option 956 sIPv6Module->setsockopt(sIPv6Protocol, IPPROTO_IPV6, IPV6_MULTICAST_IF, 957 &source->sin6_addr, sizeof(in6_addr)); 958#endif 959 960 net_buffer* clone = gBufferModule->clone(buffer, true); 961 if (clone == NULL) { 962 entry->ScheduleRemoval(); 963 return B_NO_MEMORY; 964 } 965 966 // send the ICMPv6 packet out 967 TRACE(("Sending Neighbor Solicitation\n")); 968 status = sIPv6Module->send_data(sIPv6Protocol, clone); 969 if (status < B_OK) { 970 entry->ScheduleRemoval(); 971 return status; 972 } 973 974 entry->protocol = protocol; 975 entry->timer_state = NDP_STATE_REQUEST; 976 sStackModule->set_timer(&entry->timer, 0); 977 // start request timer 978 979 *_entry = entry; 980 return B_OK; 981} 982 983 984// #pragma mark - 985 986 987static status_t 988ipv6_datalink_init(net_interface* interface, net_domain* domain, 989 net_datalink_protocol** _protocol) 990{ 991 if (domain->family != AF_INET6) 992 return B_BAD_TYPE; 993 994 status_t status = sStackModule->register_domain_device_handler( 995 interface->device, B_NET_FRAME_TYPE(IFT_ETHER, ETHER_TYPE_IPV6), domain); 996 if (status != B_OK) 997 return status; 998 999 ipv6_datalink_protocol* protocol = new(std::nothrow) ipv6_datalink_protocol; 1000 if (protocol == NULL) 1001 return B_NO_MEMORY; 1002 1003 memset(&protocol->hardware_address, 0, sizeof(sockaddr_dl)); 1004 memset(&protocol->local_address, 0, sizeof(in6_addr)); 1005 *_protocol = protocol; 1006 return B_OK; 1007} 1008 1009 1010static status_t 1011ipv6_datalink_uninit(net_datalink_protocol* protocol) 1012{ 1013 sStackModule->unregister_device_handler(protocol->interface->device, 1014 B_NET_FRAME_TYPE(IFT_ETHER, ETHER_TYPE_IPV6)); 1015 1016 delete protocol; 1017 return B_OK; 1018} 1019 1020 1021static status_t 1022ipv6_datalink_send_data(net_datalink_protocol* _protocol, net_buffer* buffer) 1023{ 1024 ipv6_datalink_protocol* protocol = (ipv6_datalink_protocol*)_protocol; 1025 1026 memcpy(buffer->source, &protocol->hardware_address, 1027 protocol->hardware_address.sdl_len); 1028 1029 if ((buffer->flags & MSG_MCAST) != 0) { 1030 sockaddr_dl multicastDestination; 1031 ipv6_to_ether_multicast(&multicastDestination, 1032 (sockaddr_in6*)buffer->destination); 1033 memcpy(buffer->destination, &multicastDestination, 1034 sizeof(sockaddr_dl)); 1035 } else { 1036 MutexLocker locker(sCacheLock); 1037 1038 // Lookup destination (we may need to wait for this) 1039 ndp_entry* entry = ndp_entry::Lookup( 1040 ((struct sockaddr_in6*)buffer->destination)->sin6_addr); 1041 if (entry == NULL) { 1042 status_t status = ndp_start_resolve(protocol, 1043 ((struct sockaddr_in6*)buffer->destination)->sin6_addr, &entry); 1044 if (status < B_OK) 1045 return status; 1046 } 1047 1048 if ((entry->flags & NDP_FLAG_REJECT) != 0) 1049 return EHOSTUNREACH; 1050 if (!(entry->flags & NDP_FLAG_VALID)) { 1051 // entry is still being resolved. 1052 TRACE(("NDP Queuing packet %p, entry still being resolved.\n", 1053 buffer)); 1054 entry->queue.Add(buffer); 1055 return B_OK; 1056 } 1057 1058 memcpy(buffer->destination, &entry->hardware_address, 1059 entry->hardware_address.sdl_len); 1060 } 1061 1062 return protocol->next->module->send_data(protocol->next, buffer); 1063} 1064 1065 1066 1067static status_t 1068ipv6_datalink_up(net_datalink_protocol* _protocol) 1069{ 1070 ipv6_datalink_protocol* protocol = (ipv6_datalink_protocol*)_protocol; 1071 status_t status = protocol->next->module->interface_up(protocol->next); 1072 if (status != B_OK) 1073 return status; 1074 1075 // cache this device's address for later use 1076 1077 status = ndp_update_local(protocol); 1078 if (status != B_OK) { 1079 protocol->next->module->interface_down(protocol->next); 1080 return status; 1081 } 1082 1083 return B_OK; 1084} 1085 1086 1087static void 1088ipv6_datalink_down(net_datalink_protocol *protocol) 1089{ 1090 // remove local NDP entries from the cache 1091 ndp_remove_local((ipv6_datalink_protocol*)protocol); 1092 1093 protocol->next->module->interface_down(protocol->next); 1094} 1095 1096 1097status_t 1098ipv6_datalink_change_address(net_datalink_protocol* _protocol, 1099 net_interface_address* address, int32 option, 1100 const struct sockaddr* oldAddress, const struct sockaddr* newAddress) 1101{ 1102 ipv6_datalink_protocol* protocol = (ipv6_datalink_protocol*)_protocol; 1103 switch (option) { 1104 case SIOCSIFADDR: 1105 case SIOCAIFADDR: 1106 case SIOCDIFADDR: 1107 // Those are the options we handle 1108 if ((protocol->interface->flags & IFF_UP) != 0) { 1109 // Update NDP entry for the local address 1110 1111 if (newAddress != NULL && newAddress->sa_family == AF_INET6) { 1112 status_t status = ndp_set_local_entry(protocol, newAddress); 1113 if (status != B_OK) 1114 return status; 1115 1116 // add IPv6 multicast route (ff00::/8) 1117 sockaddr_in6 socketAddress; 1118 memset(&socketAddress, 0, sizeof(sockaddr_in6)); 1119 socketAddress.sin6_family = AF_INET6; 1120 socketAddress.sin6_len = sizeof(sockaddr_in6); 1121 socketAddress.sin6_addr.s6_addr[0] = 0xff; 1122 1123 net_route route; 1124 memset(&route, 0, sizeof(net_route)); 1125 route.destination = (sockaddr*)&socketAddress; 1126 route.mask = (sockaddr*)&socketAddress; 1127 route.flags = 0; 1128 sDatalinkModule->add_route(address->domain, &route); 1129 } 1130 1131 if (oldAddress != NULL && oldAddress->sa_family == AF_INET6) { 1132 ndp_remove_local_entry(protocol, oldAddress, true); 1133 1134 // remove IPv6 multicast route (ff00::/8) 1135 sockaddr_in6 socketAddress; 1136 memset(&socketAddress, 0, sizeof(sockaddr_in6)); 1137 socketAddress.sin6_family = AF_INET6; 1138 socketAddress.sin6_len = sizeof(sockaddr_in6); 1139 socketAddress.sin6_addr.s6_addr[0] = 0xff; 1140 1141 net_route route; 1142 memset(&route, 0, sizeof(net_route)); 1143 route.destination = (sockaddr*)&socketAddress; 1144 route.mask = (sockaddr*)&socketAddress; 1145 route.flags = 0; 1146 sDatalinkModule->remove_route(address->domain, &route); 1147 } 1148 } 1149 break; 1150 1151 default: 1152 break; 1153 } 1154 1155 return protocol->next->module->change_address(protocol->next, address, 1156 option, oldAddress, newAddress); 1157} 1158 1159 1160static status_t 1161ipv6_datalink_control(net_datalink_protocol* protocol, int32 op, void* argument, 1162 size_t length) 1163{ 1164 return protocol->next->module->control(protocol->next, op, argument, 1165 length); 1166} 1167 1168 1169static status_t 1170ipv6_datalink_join_multicast(net_datalink_protocol* protocol, 1171 const sockaddr* address) 1172{ 1173 if (address->sa_family != AF_INET6) 1174 return EINVAL; 1175 1176 sockaddr_dl multicastAddress; 1177 ipv6_to_ether_multicast(&multicastAddress, (const sockaddr_in6*)address); 1178 1179 return protocol->next->module->join_multicast(protocol->next, 1180 (sockaddr*)&multicastAddress); 1181} 1182 1183 1184static status_t 1185ipv6_datalink_leave_multicast(net_datalink_protocol* protocol, 1186 const sockaddr* address) 1187{ 1188 if (address->sa_family != AF_INET6) 1189 return EINVAL; 1190 1191 sockaddr_dl multicastAddress; 1192 ipv6_to_ether_multicast(&multicastAddress, (const sockaddr_in6*)address); 1193 1194 return protocol->next->module->leave_multicast(protocol->next, 1195 (sockaddr*)&multicastAddress); 1196} 1197 1198 1199static status_t 1200ipv6_datalink_std_ops(int32 op, ...) 1201{ 1202 switch (op) { 1203 case B_MODULE_INIT: 1204 return ndp_init(); 1205 1206 case B_MODULE_UNINIT: 1207 return ndp_uninit(); 1208 } 1209 1210 return B_ERROR; 1211} 1212 1213 1214net_datalink_protocol_module_info gIPv6DataLinkModule = { 1215 { 1216 "network/datalink_protocols/ipv6_datagram/v1", 1217 0, 1218 ipv6_datalink_std_ops 1219 }, 1220 ipv6_datalink_init, 1221 ipv6_datalink_uninit, 1222 ipv6_datalink_send_data, 1223 ipv6_datalink_up, 1224 ipv6_datalink_down, 1225 ipv6_datalink_change_address, 1226 ipv6_datalink_control, 1227 ipv6_datalink_join_multicast, 1228 ipv6_datalink_leave_multicast, 1229}; 1230 1231net_ndp_module_info gIPv6NDPModule = { 1232 { 1233 "network/datalink_protocols/ipv6_datagram/ndp/v1", 1234 0, 1235 NULL 1236 }, 1237 ndp_receive_data 1238}; 1239 1240module_dependency module_dependencies[] = { 1241 {NET_STACK_MODULE_NAME, (module_info**)&sStackModule}, 1242 {NET_DATALINK_MODULE_NAME, (module_info**)&sDatalinkModule}, 1243 {NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule}, 1244 {"network/protocols/ipv6/v1", (module_info**)&sIPv6Module}, 1245 {} 1246}; 1247 1248module_info* modules[] = { 1249 (module_info*)&gIPv6DataLinkModule, 1250 (module_info*)&gIPv6NDPModule, 1251 NULL 1252}; 1253