* Applied next work in progress patch by Atis that takes into account most of

my comments so far. Thanks!


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37793 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2010-07-28 17:09:12 +00:00
parent 6d6408d6bc
commit b216fbd077
18 changed files with 200 additions and 100 deletions
+3 -1
View File
@@ -98,9 +98,11 @@ struct net_datalink_module_info {
struct net_route_info *info);
};
#define NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS 0x01
struct net_address_module_info {
module_info info;
bool has_broadcast_address;
uint32 flags;
status_t (*copy_address)(const sockaddr *from, sockaddr **to,
bool replaceWithZeros, const sockaddr *mask);
@@ -24,7 +24,6 @@ struct net_datalink_protocol_module_info {
status_t (*send_data)(net_datalink_protocol *self,
net_buffer *buffer);
status_t (*receive_data)(net_buffer *buffer);
status_t (*interface_up)(net_datalink_protocol *self);
void (*interface_down)(net_datalink_protocol *self);
@@ -1095,7 +1095,6 @@ static net_datalink_protocol_module_info sARPModule = {
arp_init_protocol,
arp_uninit_protocol,
arp_send_data,
NULL, // receive_data
arp_up,
arp_down,
arp_control,
@@ -210,7 +210,6 @@ static net_datalink_protocol_module_info sEthernetFrameModule = {
ethernet_frame_init,
ethernet_frame_uninit,
ethernet_frame_send_data,
NULL, // receive_data
ethernet_frame_up,
ethernet_frame_down,
ethernet_frame_control,
@@ -127,6 +127,7 @@ ipv4_datalink_std_ops(int32 op, ...)
return B_ERROR;
}
net_datalink_protocol_module_info gIPv4DataLinkModule = {
{
"network/datalink_protocols/ipv4_datagram/v1",
@@ -136,7 +137,6 @@ net_datalink_protocol_module_info gIPv4DataLinkModule = {
ipv4_datalink_init,
ipv4_datalink_uninit,
ipv4_datalink_send_data,
NULL, // receive_data
ipv4_datalink_up,
ipv4_datalink_down,
ipv4_datalink_control,
@@ -12,6 +12,7 @@ if $(TARGET_PLATFORM) != haiku {
UsePrivateKernelHeaders ;
UsePrivateHeaders kernel net ;
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols ] : true ;
KernelAddon ipv6_datagram :
ipv6_datagram.cpp
@@ -31,8 +31,9 @@
#include <new>
#include "../../protocols/ipv6/jenkins.h" // TODO: move this file
#include "../../protocols/ipv6/ipv6_address.h"
#include <ipv6/jenkins.h>
#include <ipv6/ipv6_address.h>
#include "ndp.h"
#define TRACE_NDP
@@ -83,6 +84,18 @@ struct neighbor_discovery_header {
uint8 link_address[ETHER_ADDRESS_LENGTH];
} _PACKED;
struct router_advertisement_header {
uint8 icmp6_type;
uint8 icmp6_code;
uint16 icmp6_checksum;
uint8 hop_limit;
uint8 flags;
uint16 router_lifetime;
uint32 reachable_time;
uint32 retransmit_timer;
uint8 options[];
} _PACKED;
struct ndp_entry {
ndp_entry* next;
@@ -532,8 +545,10 @@ ndp_update_local(ipv6_datalink_protocol* protocol)
static status_t
handle_neighbor_solicitation(net_buffer* buffer)
ndp_receive_solicitation(net_buffer* buffer, bool* reuseBuffer)
{
*reuseBuffer = false;
NetBufferHeaderReader<neighbor_discovery_header> bufferHeader(buffer);
if (bufferHeader.Status() < B_OK)
return bufferHeader.Status();
@@ -594,22 +609,19 @@ handle_neighbor_solicitation(net_buffer* buffer)
buffer->flags = 0;
// make sure this won't be a broadcast message
// TODO: there is not need to clone, could reuse old buffer
net_buffer* clone = gBufferModule->clone(buffer, true);
if (clone == NULL)
return B_NO_MEMORY;
if (sIPv6Protocol == NULL)
return B_ERROR;
*reuseBuffer = true;
// send the ICMPv6 packet out
TRACE(("Sending Neighbor Advertisement\n"));
return sIPv6Module->send_data(sIPv6Protocol, clone);
return sIPv6Module->send_data(sIPv6Protocol, buffer);
}
static void
handle_neighbor_advertisement(net_buffer* buffer)
ndp_receive_advertisement(net_buffer* buffer)
{
// TODO: also process unsolicited advertisments?
if ((buffer->flags & MSG_MCAST) != 0)
@@ -641,6 +653,53 @@ handle_neighbor_advertisement(net_buffer* buffer)
}
static void
ndp_receive_router_advertisement(net_buffer* buffer)
{
NetBufferHeaderReader<router_advertisement_header> bufferHeader(buffer);
if (bufferHeader.Status() < B_OK)
return;
// TODO: check for validity
// TODO: parse the options
}
static status_t
ndp_receive_data(net_buffer* buffer)
{
dprintf("ndp_receive_data\n");
NetBufferHeaderReader<icmp6_hdr> icmp6Header(buffer);
if (icmp6Header.Status() < B_OK)
return icmp6Header.Status();
bool reuseBuffer = false;
switch (icmp6Header->icmp6_type) {
case ND_NEIGHBOR_SOLICIT:
TRACE((" received Neighbor Solicitation\n"));
ndp_receive_solicitation(buffer, &reuseBuffer);
break;
case ND_NEIGHBOR_ADVERT:
TRACE((" received Neighbor Advertisement\n"));
ndp_receive_advertisement(buffer);
break;
case ND_ROUTER_ADVERT:
TRACE((" received Router Advertisement\n"));
ndp_receive_router_advertisement(buffer);
break;
}
if (reuseBuffer == false)
gBufferModule->free(buffer);
return B_OK;
}
static void
ndp_timer(struct net_timer* timer, void* data)
{
@@ -897,30 +956,6 @@ ipv6_datalink_send_data(net_datalink_protocol* _protocol, net_buffer* buffer)
}
static status_t
ipv6_datalink_receive_data(net_buffer* buffer)
{
NetBufferHeaderReader<icmp6_hdr> bufferHeader(buffer);
if (bufferHeader.Status() < B_OK)
return bufferHeader.Status();
switch (bufferHeader->icmp6_type) {
case ND_NEIGHBOR_SOLICIT:
TRACE((" received Neighbor Solicitation\n"));
handle_neighbor_solicitation(buffer);
break;
case ND_NEIGHBOR_ADVERT:
TRACE((" received Neighbor Advertisement\n"));
handle_neighbor_advertisement(buffer);
break;
}
gBufferModule->free(buffer);
return B_OK;
}
static status_t
ipv6_datalink_up(net_datalink_protocol* _protocol)
{
@@ -1058,6 +1093,7 @@ ipv6_datalink_std_ops(int32 op, ...)
return B_ERROR;
}
net_datalink_protocol_module_info gIPv6DataLinkModule = {
{
"network/datalink_protocols/ipv6_datagram/v1",
@@ -1067,7 +1103,6 @@ net_datalink_protocol_module_info gIPv6DataLinkModule = {
ipv6_datalink_init,
ipv6_datalink_uninit,
ipv6_datalink_send_data,
ipv6_datalink_receive_data,
ipv6_datalink_up,
ipv6_datalink_down,
ipv6_datalink_control,
@@ -1075,6 +1110,14 @@ net_datalink_protocol_module_info gIPv6DataLinkModule = {
ipv6_datalink_leave_multicast,
};
net_ndp_module_info gIPv6NDPModule = {
{
"network/datalink_protocols/ipv6_datagram/ndp/v1",
0,
NULL
},
ndp_receive_data
};
module_dependency module_dependencies[] = {
{NET_STACK_MODULE_NAME, (module_info**)&sStackModule},
@@ -1085,5 +1128,6 @@ module_dependency module_dependencies[] = {
module_info* modules[] = {
(module_info*)&gIPv6DataLinkModule,
(module_info*)&gIPv6NDPModule,
NULL
};
@@ -0,0 +1,19 @@
/*
* Copyright 2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef IPV6_NDP_H
#define IPV6_NDP_H
#include <net_buffer.h>
struct net_ndp_module_info {
module_info info;
status_t (*receive_data)(net_buffer* buffer);
};
#endif // IPV6_NDP_H
@@ -171,7 +171,6 @@ static net_datalink_protocol_module_info sLoopbackFrameModule = {
loopback_frame_init,
loopback_frame_uninit,
loopback_frame_send_data,
NULL, // receive_data
loopback_frame_up,
loopback_frame_down,
loopback_frame_control,
@@ -11,6 +11,8 @@ if $(TARGET_PLATFORM) != haiku {
}
UsePrivateHeaders kernel net ;
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols ] : true ;
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network datalink_protocols ] : true ;
KernelAddon icmp6 :
icmp6.cpp
@@ -8,6 +8,7 @@
#include <net_protocol.h>
#include <net_stack.h>
#include <net_datalink_protocol.h>
#include <NetUtilities.h>
#include <NetBufferUtilities.h>
#include <KernelExport.h>
@@ -19,7 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include "../ipv6/ipv6_utils.h" // ipv6_checksum()
#include <ipv6_datagram/ndp.h>
#define TRACE_ICMP6
@@ -35,7 +36,7 @@ typedef NetBufferField<uint16, offsetof(icmp6_hdr, icmp6_cksum)> ICMP6ChecksumFi
net_buffer_module_info *gBufferModule;
static net_stack_module_info *sStackModule;
static net_datalink_protocol_module_info *sIPv6DatalinkModule;
static net_ndp_module_info *sIPv6NDPModule;
net_protocol *
@@ -212,17 +213,22 @@ icmp6_receive_data(net_buffer *buffer)
TRACE((" got type %u, code %u, checksum 0x%x\n", header.icmp6_type,
header.icmp6_code, header.icmp6_cksum));
net_domain* domain;
if (buffer->interface != NULL)
domain = buffer->interface->domain;
else
domain = sStackModule->get_domain(buffer->source->sa_family);
// TODO: possible?
if (domain == NULL || domain->module == NULL)
return B_ERROR;
net_address_module_info* addressModule = domain->address_module;
// compute and check the checksum
uint16 checksum;
checksum = gBufferModule->checksum(buffer, 0, buffer->size, false);
checksum = ipv6_checksum(&((sockaddr_in6*)buffer->source)->sin6_addr,
&((sockaddr_in6*)buffer->destination)->sin6_addr,
buffer->size, IPPROTO_ICMPV6, checksum);
TRACE((" computed checksum: %ld\n", checksum));
if (checksum != 0)
return B_BAD_DATA;
if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer,
IPPROTO_ICMPV6) != 0)
return B_BAD_DATA;
switch (header.icmp6_type) {
case ICMP6_ECHO_REPLY:
@@ -230,20 +236,13 @@ icmp6_receive_data(net_buffer *buffer)
case ICMP6_ECHO_REQUEST:
{
net_domain *domain;
if (buffer->interface != NULL) {
domain = buffer->interface->domain;
// We only reply to echo requests of our local interface; we
// don't reply to broadcast requests
if (!domain->address_module->equal_addresses(
buffer->interface->address, buffer->destination))
break;
} else
domain = sStackModule->get_domain(buffer->source->sa_family);
if (domain == NULL || domain->module == NULL)
break;
}
net_buffer *reply = gBufferModule->duplicate(buffer);
if (reply == NULL)
@@ -260,11 +259,8 @@ icmp6_receive_data(net_buffer *buffer)
header.Sync();
checksum = gBufferModule->checksum(buffer, 0, buffer->size, false);
*ICMP6ChecksumField(reply) =
ipv6_checksum(&((sockaddr_in6*)buffer->source)->sin6_addr,
&((sockaddr_in6*)buffer->destination)->sin6_addr,
buffer->size, IPPROTO_ICMPV6, checksum);
*ICMP6ChecksumField(reply) = Checksum::PseudoHeader(addressModule,
gBufferModule, buffer, IPPROTO_ICMPV6);
status_t status = domain->module->send_data(NULL, reply);
if (status < B_OK) {
@@ -274,8 +270,8 @@ icmp6_receive_data(net_buffer *buffer)
}
default:
// forward unrecognized messages to datalink layer
return sIPv6DatalinkModule->receive_data(buffer);
// unrecognized messages go to neighbor discovery protocol handler
return sIPv6NDPModule->receive_data(buffer);
}
gBufferModule->free(buffer);
@@ -383,8 +379,8 @@ net_protocol_module_info sICMP6Module = {
module_dependency module_dependencies[] = {
{NET_STACK_MODULE_NAME, (module_info **)&sStackModule},
{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
{"network/datalink_protocols/ipv6_datagram/v1",
(module_info **)&sIPv6DatalinkModule},
{"network/datalink_protocols/ipv6_datagram/ndp/v1",
(module_info **)&sIPv6NDPModule},
{}
};
@@ -507,7 +507,7 @@ net_address_module_info gIPv4AddressModule = {
0,
NULL
},
true, // has_broadcast_address
NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS,
ipv4_copy_address,
ipv4_mask_address,
ipv4_equal_addresses,
@@ -52,13 +52,13 @@
struct IPv6Header {
struct ip6_hdr h;
struct ip6_hdr header;
uint8 ProtocolVersion() const { return h.ip6_vfc & IPV6_VERSION_MASK; }
uint8 ServiceType() const { return ntohl(h.ip6_flow) >> 20;}
uint16 PayloadLength() const { return ntohs(h.ip6_plen); }
const in6_addr& Dst() const { return h.ip6_dst; }
const in6_addr& Src() const { return h.ip6_src; }
uint8 ProtocolVersion() const { return header.ip6_vfc & IPV6_VERSION_MASK; }
uint8 ServiceType() const { return ntohl(header.ip6_flow) >> 20;}
uint16 PayloadLength() const { return ntohs(header.ip6_plen); }
const in6_addr& Dst() const { return header.ip6_dst; }
const in6_addr& Src() const { return header.ip6_src; }
uint16 GetTransportHeaderOffset(net_buffer* buffer) const;
};
@@ -139,7 +139,7 @@ uint16
IPv6Header::GetTransportHeaderOffset(net_buffer* buffer) const
{
uint16 offset = sizeof(struct ip6_hdr);
uint8 next = h.ip6_nxt;
uint8 next = header.ip6_nxt;
// these are the extension headers that might be supported one day
while (next == IPPROTO_HOPOPTS
@@ -192,10 +192,11 @@ dump_ipv6_header(IPv6Header &header)
dprintf(" version: %d\n", header.ProtocolVersion() >> 4);
dprintf(" service_type: %d\n", header.ServiceType());
dprintf(" payload_length: %d\n", header.PayloadLength());
dprintf(" next_header: %d\n", header.h.ip6_nxt);
dprintf(" hop_limit: %d\n", header.h.ip6_hops);
dprintf(" source: %s\n", ip6_sprintf(&header.h.ip6_src, addrbuf));
dprintf(" destination: %s\n", ip6_sprintf(&header.h.ip6_dst, addrbuf));
dprintf(" next_header: %d\n", header.header.ip6_nxt);
dprintf(" hop_limit: %d\n", header.header.ip6_hops);
dprintf(" source: %s\n", ip6_sprintf(&header.header.ip6_src, addrbuf));
dprintf(" destination: %s\n",
ip6_sprintf(&header.header.ip6_dst, addrbuf));
#endif
}
@@ -968,8 +969,6 @@ ipv6_receive_data(net_buffer* buffer)
uint16 transportHeaderOffset = header.GetTransportHeaderOffset(buffer);
uint8 protocol = buffer->protocol;
buffer->hoplimit = header.h.ip6_hlim;
// remove any trailing/padding data
status_t status = gBufferModule->trim(buffer, packetLength);
if (status != B_OK)
@@ -979,8 +978,15 @@ ipv6_receive_data(net_buffer* buffer)
// TODO: check for fragmentation
//
// tell the buffer to preserve removed ipv6 header - may need it later
gBufferModule->store_header(buffer);
TRACE("store_header for %p\n", buffer);
// remove ipv6 headers for now
gBufferModule->remove_header(buffer, transportHeaderOffset);
// deliver the data to raw sockets
raw_receive_data(buffer);
net_protocol_module_info* module = receiving_protocol(protocol);
@@ -1029,30 +1035,45 @@ ipv6_error_reply(net_protocol* protocol, net_buffer* causedError, uint32 code,
ssize_t
ipv6_process_ancillary_data_no_container(net_protocol* protocol,
ipv6_process_ancillary_data_no_container(net_protocol* _protocol,
net_buffer* buffer, void* msgControl, size_t msgControlLen)
{
ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
ssize_t bytesWritten = 0;
if (((ipv6_protocol*)protocol)->receive_hoplimit != 0) {
if (protocol->receive_hoplimit != 0) {
TRACE("receive_hoplimit");
if (msgControlLen < CMSG_SPACE(sizeof(int)))
return B_NO_MEMORY;
TRACE("restore_header for %p\n", buffer);
if (gBufferModule->stored_header_length(buffer)
< (int)sizeof(ip6_hdr))
return B_ERROR;
IPv6Header header;
if (gBufferModule->restore_header(buffer, 0, &header, sizeof(ip6_hdr))
!= B_OK)
return B_ERROR;
if (header.ProtocolVersion() != IPV6_VERSION)
return B_ERROR;
cmsghdr* messageHeader = (cmsghdr*)((char*)msgControl + bytesWritten);
messageHeader->cmsg_len = CMSG_LEN(sizeof(int));
messageHeader->cmsg_level = IPPROTO_IPV6;
messageHeader->cmsg_type = IPV6_HOPLIMIT;
int hoplimit = buffer->hoplimit;
int hoplimit = header.header.ip6_hlim;
memcpy(CMSG_DATA(messageHeader), &hoplimit, sizeof(int));
bytesWritten += CMSG_SPACE(sizeof(int));
msgControlLen -= CMSG_SPACE(sizeof(int));
}
if (((ipv6_protocol*)protocol)->receive_pktinfo != 0) {
if (protocol->receive_pktinfo != 0) {
TRACE("receive_pktinfo");
if (msgControlLen < CMSG_SPACE(sizeof(struct in6_pktinfo)))
@@ -1161,7 +1182,6 @@ ipv6_std_ops(int32 op, ...)
return init_ipv6();
case B_MODULE_UNINIT:
return uninit_ipv6();
default:
return B_ERROR;
}
@@ -247,8 +247,8 @@ ipv6_first_mask_bit(const sockaddr *_mask)
continue;
for (uint8 bit = 0; bit < 8; bit++) {
if (pmask[i] & (1 << bit))
return bit;
if ((pmask[i] & (1 << (7 - bit))) == 0)
return i * 8 + bit;
}
}
@@ -276,7 +276,7 @@ ipv6_check_mask(const sockaddr *_mask)
} else if (pmask[i] == 0) {
zero = true;
} else {
for (int8 bit = 7; bit > 0; bit--) {
for (int8 bit = 7; bit >= 0; bit--) {
if (pmask[i] & (1 << bit)) {
if (zero)
return false;
@@ -520,8 +520,8 @@ ipv6_checksum_address(struct Checksum *checksum, const sockaddr *address)
return B_BAD_VALUE;
in6_addr &a = ((sockaddr_in6 *)address)->sin6_addr;
for (uint32 i = 0; i < sizeof(in6_addr); i++)
(*checksum) << a.s6_addr[i];
for (uint32 i = 0; i < sizeof(in6_addr); i += 2)
(*checksum) << *(uint16*)(a.s6_addr + i);
return B_OK;
}
@@ -544,7 +544,7 @@ net_address_module_info gIPv6AddressModule = {
0,
NULL
},
false, // has_broadcast_address
0, // flags
ipv6_copy_address,
ipv6_mask_address,
ipv6_equal_addresses,
@@ -413,7 +413,7 @@ net_address_module_info gL2cap4AddressModule = {
0,
NULL
},
true, // has_broadcast_address
NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS,
l2cap_copy_address,
l2cap_mask_address,
l2cap_equal_addresses,
@@ -756,6 +756,13 @@ tcp_init()
NULL);
if (status < B_OK)
return status;
status = gStackModule->register_domain_protocols(AF_INET6,
SOCK_STREAM, 0,
"network/protocols/tcp/v1",
"network/protocols/ipv6/v1",
NULL);
if (status < B_OK)
return status;
status = gStackModule->register_domain_protocols(AF_INET, SOCK_STREAM,
IPPROTO_TCP,
@@ -764,11 +771,22 @@ tcp_init()
NULL);
if (status < B_OK)
return status;
status = gStackModule->register_domain_protocols(AF_INET6, SOCK_STREAM,
IPPROTO_TCP,
"network/protocols/tcp/v1",
"network/protocols/ipv6/v1",
NULL);
if (status < B_OK)
return status;
status = gStackModule->register_domain_receiving_protocol(AF_INET,
IPPROTO_TCP, "network/protocols/tcp/v1");
if (status < B_OK)
return status;
status = gStackModule->register_domain_receiving_protocol(AF_INET6,
IPPROTO_TCP, "network/protocols/tcp/v1");
if (status < B_OK)
return status;
add_debugger_command("tcp_endpoints", dump_endpoints,
"lists all open TCP endpoints");
@@ -290,7 +290,7 @@ net_address_module_info gAddressModule = {
0,
NULL
},
true, // has_broadcast_address
NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS,
unix_copy_address,
unix_mask_address,
unix_equal_addresses,
@@ -30,7 +30,9 @@
#include <stdio.h>
#include <string.h>
#include <netinet6/in6.h> // TODO
// TODO: this is only needed for IPv6 multicast route code;
// remove it when the code will be refactored
#include <netinet6/in6.h>
struct datalink_protocol : net_protocol {
@@ -752,7 +754,8 @@ interface_protocol_control(net_datalink_protocol* _protocol, int32 option,
// reset the broadcast address if the address family has such
sockaddr* broadcast;
if (interface->domain->address_module->has_broadcast_address) {
if ((interface->domain->address_module->flags
& NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0) {
broadcast = reallocate_address(&interface->destination,
request.ifr_addr.sa_len);
} else {
@@ -971,7 +974,6 @@ net_datalink_protocol_module_info gDatalinkInterfaceProtocolModule = {
interface_protocol_init,
interface_protocol_uninit,
interface_protocol_send_data,
NULL, // receive_data
interface_protocol_up,
interface_protocol_down,
interface_protocol_control,