made IPv4's send path be multicast aware.
- also added IP_MULTICAST_TTL support. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20693 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -780,8 +780,6 @@ arp_uninit_protocol(net_datalink_protocol *protocol)
|
|||||||
{
|
{
|
||||||
sStackModule->unregister_device_handler(protocol->interface->device,
|
sStackModule->unregister_device_handler(protocol->interface->device,
|
||||||
ETHER_FRAME_TYPE | ETHER_TYPE_ARP);
|
ETHER_FRAME_TYPE | ETHER_TYPE_ARP);
|
||||||
sStackModule->unregister_device_handler(protocol->interface->device,
|
|
||||||
ETHER_FRAME_TYPE | ETHER_TYPE_IP);
|
|
||||||
|
|
||||||
delete protocol;
|
delete protocol;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -806,7 +804,30 @@ arp_send_data(net_datalink_protocol *protocol,
|
|||||||
memcpy(&buffer->source, &entry->hardware_address,
|
memcpy(&buffer->source, &entry->hardware_address,
|
||||||
entry->hardware_address.sdl_len);
|
entry->hardware_address.sdl_len);
|
||||||
|
|
||||||
if ((buffer->flags & MSG_BCAST) == 0) {
|
if (buffer->flags & MSG_MCAST) {
|
||||||
|
// RFC 1112 - Host extensions for IP multicasting
|
||||||
|
//
|
||||||
|
// ``An IP host group address is mapped to an Ethernet multicast
|
||||||
|
// address by placing the low-order 23-bits of the IP address into
|
||||||
|
// the low-order 23 bits of the Ethernet multicast address
|
||||||
|
// 01-00-5E-00-00-00 (hex).''
|
||||||
|
|
||||||
|
sockaddr_dl *destination = (sockaddr_dl *)&buffer->destination;
|
||||||
|
|
||||||
|
memmove(((uint8 *)destination->sdl_data) + 2,
|
||||||
|
&((sockaddr_in *)&buffer->destination)->sin_addr, sizeof(in_addr));
|
||||||
|
|
||||||
|
destination->sdl_len = sizeof(sockaddr_dl);
|
||||||
|
destination->sdl_family = AF_DLI;
|
||||||
|
destination->sdl_index = 0;
|
||||||
|
destination->sdl_type = IFT_ETHER;
|
||||||
|
destination->sdl_e_type = ETHER_TYPE_IP;
|
||||||
|
destination->sdl_nlen = destination->sdl_slen = 0;
|
||||||
|
destination->sdl_alen = ETHER_ADDRESS_LENGTH;
|
||||||
|
|
||||||
|
uint32 *data = (uint32 *)destination->sdl_data;
|
||||||
|
data[0] = (data[0] & htonl(0x7f)) | htonl(0x01005e00);
|
||||||
|
} else if ((buffer->flags & MSG_BCAST) == 0) {
|
||||||
// Lookup destination (we may need to wait for this)
|
// Lookup destination (we may need to wait for this)
|
||||||
entry = arp_entry::Lookup(
|
entry = arp_entry::Lookup(
|
||||||
((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr);
|
((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr);
|
||||||
|
|||||||
@@ -146,15 +146,20 @@ struct ipv4_protocol : net_protocol {
|
|||||||
RawSocket *raw;
|
RawSocket *raw;
|
||||||
uint8 service_type;
|
uint8 service_type;
|
||||||
uint8 time_to_live;
|
uint8 time_to_live;
|
||||||
|
uint8 multicast_time_to_live;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
|
|
||||||
MulticastFilter<in_addr> multicast_filter;
|
MulticastFilter<in_addr> multicast_filter;
|
||||||
};
|
};
|
||||||
|
|
||||||
// protocol flags
|
// protocol flags
|
||||||
#define IP_FLAG_HEADER_INCLUDED 0x01
|
#define IP_FLAG_HEADER_INCLUDED 0x01
|
||||||
|
|
||||||
|
|
||||||
|
static const int kDefaultTTL = 254;
|
||||||
|
static const int kDefaultMulticastTTL = 1;
|
||||||
|
|
||||||
|
|
||||||
extern net_protocol_module_info gIPv4Module;
|
extern net_protocol_module_info gIPv4Module;
|
||||||
// we need this in ipv4_std_ops() for registering the AF_INET domain
|
// we need this in ipv4_std_ops() for registering the AF_INET domain
|
||||||
|
|
||||||
@@ -699,6 +704,16 @@ receiving_protocol(uint8 protocol)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
fill_sockaddr_in(sockaddr_in *target, in_addr_t address)
|
||||||
|
{
|
||||||
|
memset(target, 0, sizeof(sockaddr_in));
|
||||||
|
target->sin_family = AF_INET;
|
||||||
|
target->sin_len = sizeof(sockaddr_in);
|
||||||
|
target->sin_addr.s_addr = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
ipv4_delta_group(MulticastFilter<in_addr>::GroupState *group, int option,
|
ipv4_delta_group(MulticastFilter<in_addr>::GroupState *group, int option,
|
||||||
net_interface *interface, const in_addr *sourceAddr)
|
net_interface *interface, const in_addr *sourceAddr)
|
||||||
@@ -771,11 +786,7 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
|||||||
interface = sDatalinkModule->get_interface_with_address(sDomain, NULL);
|
interface = sDatalinkModule->get_interface_with_address(sDomain, NULL);
|
||||||
} else {
|
} else {
|
||||||
sockaddr_in address;
|
sockaddr_in address;
|
||||||
|
fill_sockaddr_in(&address, interfaceAddr->s_addr);
|
||||||
memset(&address, 0, sizeof(address));
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_len = sizeof(address);
|
|
||||||
address.sin_addr = *interfaceAddr;
|
|
||||||
|
|
||||||
interface = sDatalinkModule->get_interface_with_address(sDomain,
|
interface = sDatalinkModule->get_interface_with_address(sDomain,
|
||||||
(sockaddr *)&address);
|
(sockaddr *)&address);
|
||||||
@@ -828,7 +839,8 @@ ipv4_init_protocol(net_socket *socket)
|
|||||||
|
|
||||||
protocol->raw = NULL;
|
protocol->raw = NULL;
|
||||||
protocol->service_type = 0;
|
protocol->service_type = 0;
|
||||||
protocol->time_to_live = 254;
|
protocol->time_to_live = kDefaultTTL;
|
||||||
|
protocol->multicast_time_to_live = kDefaultMulticastTTL;
|
||||||
protocol->flags = 0;
|
protocol->flags = 0;
|
||||||
return protocol;
|
return protocol;
|
||||||
}
|
}
|
||||||
@@ -914,6 +926,32 @@ ipv4_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
get_int_option(void *target, size_t length, int value)
|
||||||
|
{
|
||||||
|
if (length != sizeof(int))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
return user_memcpy(target, &value, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Type> static status_t
|
||||||
|
set_int_option(Type &target, void *_value, size_t length)
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
|
||||||
|
if (length != sizeof(int))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (user_memcpy(&value, _value, sizeof(int)) < B_OK)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
target = value;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||||
size_t *_length)
|
size_t *_length)
|
||||||
@@ -928,31 +966,18 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
|||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case IP_HDRINCL:
|
case IP_HDRINCL:
|
||||||
{
|
return get_int_option(value, *_length,
|
||||||
if (*_length != sizeof(int))
|
(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
int headerIncluded = (protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0;
|
|
||||||
return user_memcpy(value, &headerIncluded, sizeof(headerIncluded));
|
|
||||||
}
|
|
||||||
|
|
||||||
case IP_TTL:
|
case IP_TTL:
|
||||||
{
|
return get_int_option(value, *_length, protocol->time_to_live);
|
||||||
if (*_length != sizeof(int))
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
int timeToLive = protocol->time_to_live;
|
|
||||||
return user_memcpy(value, &timeToLive, sizeof(timeToLive));
|
|
||||||
}
|
|
||||||
|
|
||||||
case IP_TOS:
|
case IP_TOS:
|
||||||
{
|
return get_int_option(value, *_length, protocol->service_type);
|
||||||
if (*_length != sizeof(int))
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
int serviceType = protocol->service_type;
|
case IP_MULTICAST_TTL:
|
||||||
return user_memcpy(value, &serviceType, sizeof(serviceType));
|
return get_int_option(value, *_length,
|
||||||
}
|
protocol->multicast_time_to_live);
|
||||||
|
|
||||||
case IP_ADD_MEMBERSHIP:
|
case IP_ADD_MEMBERSHIP:
|
||||||
case IP_DROP_MEMBERSHIP:
|
case IP_DROP_MEMBERSHIP:
|
||||||
@@ -996,28 +1021,14 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case IP_TTL:
|
case IP_TTL:
|
||||||
{
|
return set_int_option(protocol->time_to_live, value, *_length);
|
||||||
int timeToLive;
|
|
||||||
if (*_length != sizeof(int))
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
if (user_memcpy(&timeToLive, value, sizeof(timeToLive)) < B_OK)
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
|
|
||||||
protocol->time_to_live = timeToLive;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
case IP_TOS:
|
case IP_TOS:
|
||||||
{
|
return set_int_option(protocol->service_type, value, *_length);
|
||||||
int serviceType;
|
|
||||||
if (*_length != sizeof(int))
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
if (user_memcpy(&serviceType, value, sizeof(serviceType)) < B_OK)
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
|
|
||||||
protocol->service_type = serviceType;
|
case IP_MULTICAST_TTL:
|
||||||
return B_OK;
|
return set_int_option(protocol->multicast_time_to_live, value,
|
||||||
}
|
*_length);
|
||||||
|
|
||||||
case IP_ADD_MEMBERSHIP:
|
case IP_ADD_MEMBERSHIP:
|
||||||
case IP_DROP_MEMBERSHIP:
|
case IP_DROP_MEMBERSHIP:
|
||||||
@@ -1148,6 +1159,19 @@ ipv4_send_routed_data(net_protocol *_protocol, struct net_route *route,
|
|||||||
if (protocol != NULL)
|
if (protocol != NULL)
|
||||||
headerIncluded = (protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0;
|
headerIncluded = (protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0;
|
||||||
|
|
||||||
|
buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
|
||||||
|
|
||||||
|
if (destination.sin_addr.s_addr == INADDR_ANY)
|
||||||
|
return EDESTADDRREQ;
|
||||||
|
else if (destination.sin_addr.s_addr == INADDR_BROADCAST) {
|
||||||
|
// TODO check for local broadcast addresses as well?
|
||||||
|
if (protocol && !(protocol->socket->options & SO_BROADCAST))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
buffer->flags |= MSG_BCAST;
|
||||||
|
} else if (IN_MULTICAST(destination.sin_addr.s_addr)) {
|
||||||
|
buffer->flags |= MSG_MCAST;
|
||||||
|
}
|
||||||
|
|
||||||
// Add IP header (if needed)
|
// Add IP header (if needed)
|
||||||
|
|
||||||
if (!headerIncluded) {
|
if (!headerIncluded) {
|
||||||
@@ -1161,7 +1185,12 @@ ipv4_send_routed_data(net_protocol *_protocol, struct net_route *route,
|
|||||||
header->total_length = htons(buffer->size);
|
header->total_length = htons(buffer->size);
|
||||||
header->id = htons(atomic_add(&sPacketID, 1));
|
header->id = htons(atomic_add(&sPacketID, 1));
|
||||||
header->fragment_offset = 0;
|
header->fragment_offset = 0;
|
||||||
header->time_to_live = protocol ? protocol->time_to_live : 254;
|
if (protocol)
|
||||||
|
header->time_to_live = (buffer->flags & MSG_MCAST) ?
|
||||||
|
protocol->multicast_time_to_live : protocol->time_to_live;
|
||||||
|
else
|
||||||
|
header->time_to_live = (buffer->flags & MSG_MCAST) ?
|
||||||
|
kDefaultMulticastTTL : kDefaultTTL;
|
||||||
header->protocol = protocol ? protocol->socket->protocol : buffer->protocol;
|
header->protocol = protocol ? protocol->socket->protocol : buffer->protocol;
|
||||||
header->checksum = 0;
|
header->checksum = 0;
|
||||||
|
|
||||||
@@ -1206,18 +1235,25 @@ ipv4_send_routed_data(net_protocol *_protocol, struct net_route *route,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ipv4_send_data(net_protocol *protocol, net_buffer *buffer)
|
ipv4_send_data(net_protocol *_protocol, net_buffer *buffer)
|
||||||
{
|
{
|
||||||
|
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
||||||
|
|
||||||
TRACE_SK(protocol, "SendData(%p [%ld bytes])", buffer, buffer->size);
|
TRACE_SK(protocol, "SendData(%p [%ld bytes])", buffer, buffer->size);
|
||||||
|
|
||||||
sockaddr_in &destination = *(sockaddr_in *)&buffer->destination;
|
if (protocol) {
|
||||||
|
if (protocol->flags & IP_FLAG_HEADER_INCLUDED) {
|
||||||
|
if (buffer->size < sizeof(ipv4_header))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
if (destination.sin_len == 0 || destination.sin_addr.s_addr == INADDR_ANY)
|
sockaddr_in *source = (sockaddr_in *)&buffer->source;
|
||||||
return EDESTADDRREQ;
|
sockaddr_in *destination = (sockaddr_in *)&buffer->destination;
|
||||||
else if (destination.sin_addr.s_addr == INADDR_BROADCAST) {
|
|
||||||
// TODO check for local broadcast addresses as well?
|
fill_sockaddr_in(source, *NetBufferField<in_addr_t,
|
||||||
if (protocol && !(protocol->socket->options & SO_BROADCAST))
|
offsetof(ipv4_header, source)>(buffer));
|
||||||
return B_BAD_VALUE;
|
fill_sockaddr_in(destination, *NetBufferField<in_addr_t,
|
||||||
|
offsetof(ipv4_header, destination)>(buffer));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
net_route *route = NULL;
|
net_route *route = NULL;
|
||||||
@@ -1319,13 +1355,8 @@ ipv4_receive_data(net_buffer *buffer)
|
|||||||
struct sockaddr_in &source = *(struct sockaddr_in *)&buffer->source;
|
struct sockaddr_in &source = *(struct sockaddr_in *)&buffer->source;
|
||||||
struct sockaddr_in &destination = *(struct sockaddr_in *)&buffer->destination;
|
struct sockaddr_in &destination = *(struct sockaddr_in *)&buffer->destination;
|
||||||
|
|
||||||
source.sin_len = sizeof(sockaddr_in);
|
fill_sockaddr_in(&source, header.source);
|
||||||
source.sin_family = AF_INET;
|
fill_sockaddr_in(&destination, header.destination);
|
||||||
source.sin_addr.s_addr = header.source;
|
|
||||||
|
|
||||||
destination.sin_len = sizeof(sockaddr_in);
|
|
||||||
destination.sin_family = AF_INET;
|
|
||||||
destination.sin_addr.s_addr = header.destination;
|
|
||||||
|
|
||||||
// lower layers notion of Broadcast or Multicast have no relevance to us
|
// lower layers notion of Broadcast or Multicast have no relevance to us
|
||||||
buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
|
buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
|
||||||
|
|||||||
Reference in New Issue
Block a user