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:
parent
d3be414572
commit
629878443b
@ -780,8 +780,6 @@ arp_uninit_protocol(net_datalink_protocol *protocol)
|
||||
{
|
||||
sStackModule->unregister_device_handler(protocol->interface->device,
|
||||
ETHER_FRAME_TYPE | ETHER_TYPE_ARP);
|
||||
sStackModule->unregister_device_handler(protocol->interface->device,
|
||||
ETHER_FRAME_TYPE | ETHER_TYPE_IP);
|
||||
|
||||
delete protocol;
|
||||
return B_OK;
|
||||
@ -806,7 +804,30 @@ arp_send_data(net_datalink_protocol *protocol,
|
||||
memcpy(&buffer->source, &entry->hardware_address,
|
||||
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)
|
||||
entry = arp_entry::Lookup(
|
||||
((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr);
|
||||
|
@ -146,15 +146,20 @@ struct ipv4_protocol : net_protocol {
|
||||
RawSocket *raw;
|
||||
uint8 service_type;
|
||||
uint8 time_to_live;
|
||||
uint8 multicast_time_to_live;
|
||||
uint32 flags;
|
||||
|
||||
MulticastFilter<in_addr> multicast_filter;
|
||||
MulticastFilter<in_addr> multicast_filter;
|
||||
};
|
||||
|
||||
// protocol flags
|
||||
#define IP_FLAG_HEADER_INCLUDED 0x01
|
||||
|
||||
|
||||
static const int kDefaultTTL = 254;
|
||||
static const int kDefaultMulticastTTL = 1;
|
||||
|
||||
|
||||
extern net_protocol_module_info gIPv4Module;
|
||||
// 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
|
||||
ipv4_delta_group(MulticastFilter<in_addr>::GroupState *group, int option,
|
||||
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);
|
||||
} else {
|
||||
sockaddr_in address;
|
||||
|
||||
memset(&address, 0, sizeof(address));
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_len = sizeof(address);
|
||||
address.sin_addr = *interfaceAddr;
|
||||
fill_sockaddr_in(&address, interfaceAddr->s_addr);
|
||||
|
||||
interface = sDatalinkModule->get_interface_with_address(sDomain,
|
||||
(sockaddr *)&address);
|
||||
@ -828,7 +839,8 @@ ipv4_init_protocol(net_socket *socket)
|
||||
|
||||
protocol->raw = NULL;
|
||||
protocol->service_type = 0;
|
||||
protocol->time_to_live = 254;
|
||||
protocol->time_to_live = kDefaultTTL;
|
||||
protocol->multicast_time_to_live = kDefaultMulticastTTL;
|
||||
protocol->flags = 0;
|
||||
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
|
||||
ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
size_t *_length)
|
||||
@ -928,31 +966,18 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
|
||||
switch (option) {
|
||||
case IP_HDRINCL:
|
||||
{
|
||||
if (*_length != sizeof(int))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
int headerIncluded = (protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0;
|
||||
return user_memcpy(value, &headerIncluded, sizeof(headerIncluded));
|
||||
}
|
||||
return get_int_option(value, *_length,
|
||||
(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
|
||||
|
||||
case IP_TTL:
|
||||
{
|
||||
if (*_length != sizeof(int))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
int timeToLive = protocol->time_to_live;
|
||||
return user_memcpy(value, &timeToLive, sizeof(timeToLive));
|
||||
}
|
||||
return get_int_option(value, *_length, protocol->time_to_live);
|
||||
|
||||
case IP_TOS:
|
||||
{
|
||||
if (*_length != sizeof(int))
|
||||
return B_BAD_VALUE;
|
||||
return get_int_option(value, *_length, protocol->service_type);
|
||||
|
||||
int serviceType = protocol->service_type;
|
||||
return user_memcpy(value, &serviceType, sizeof(serviceType));
|
||||
}
|
||||
case IP_MULTICAST_TTL:
|
||||
return get_int_option(value, *_length,
|
||||
protocol->multicast_time_to_live);
|
||||
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
@ -996,28 +1021,14 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
}
|
||||
|
||||
case IP_TTL:
|
||||
{
|
||||
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;
|
||||
}
|
||||
return set_int_option(protocol->time_to_live, value, *_length);
|
||||
|
||||
case IP_TOS:
|
||||
{
|
||||
int serviceType;
|
||||
if (*_length != sizeof(int))
|
||||
return B_BAD_VALUE;
|
||||
if (user_memcpy(&serviceType, value, sizeof(serviceType)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
return set_int_option(protocol->service_type, value, *_length);
|
||||
|
||||
protocol->service_type = serviceType;
|
||||
return B_OK;
|
||||
}
|
||||
case IP_MULTICAST_TTL:
|
||||
return set_int_option(protocol->multicast_time_to_live, value,
|
||||
*_length);
|
||||
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
@ -1148,6 +1159,19 @@ ipv4_send_routed_data(net_protocol *_protocol, struct net_route *route,
|
||||
if (protocol != NULL)
|
||||
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)
|
||||
|
||||
if (!headerIncluded) {
|
||||
@ -1161,7 +1185,12 @@ ipv4_send_routed_data(net_protocol *_protocol, struct net_route *route,
|
||||
header->total_length = htons(buffer->size);
|
||||
header->id = htons(atomic_add(&sPacketID, 1));
|
||||
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->checksum = 0;
|
||||
|
||||
@ -1206,18 +1235,25 @@ ipv4_send_routed_data(net_protocol *_protocol, struct net_route *route,
|
||||
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
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;
|
||||
sockaddr_in *source = (sockaddr_in *)&buffer->source;
|
||||
sockaddr_in *destination = (sockaddr_in *)&buffer->destination;
|
||||
|
||||
fill_sockaddr_in(source, *NetBufferField<in_addr_t,
|
||||
offsetof(ipv4_header, source)>(buffer));
|
||||
fill_sockaddr_in(destination, *NetBufferField<in_addr_t,
|
||||
offsetof(ipv4_header, destination)>(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
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 &destination = *(struct sockaddr_in *)&buffer->destination;
|
||||
|
||||
source.sin_len = sizeof(sockaddr_in);
|
||||
source.sin_family = AF_INET;
|
||||
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;
|
||||
fill_sockaddr_in(&source, header.source);
|
||||
fill_sockaddr_in(&destination, header.destination);
|
||||
|
||||
// lower layers notion of Broadcast or Multicast have no relevance to us
|
||||
buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
|
||||
|
Loading…
x
Reference in New Issue
Block a user