Applied patch by Ma Jie adding functionality needed by mDNSResponder:

* added new protocol method process_ancillary_data_no_container() that does not
  need a container to fill the cmsghdr data.
* Added support for the IP_RECVDSTADDR option using this call.
* Implemented support for IP_MULTICAST_IF.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31585 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-07-15 11:53:29 +00:00
parent ecece29dd8
commit 78888c44da
8 changed files with 154 additions and 4 deletions

View File

@ -79,6 +79,8 @@ struct net_protocol_module_info {
ssize_t (*process_ancillary_data)(net_protocol *self,
const ancillary_data_header *header, const void *data,
void *buffer, size_t bufferSize);
ssize_t (*process_ancillary_data_no_container)(net_protocol *self,
net_buffer *buffer, void *buffer, size_t bufferSize);
ssize_t (*send_data_no_buffer)(net_protocol *self, const iovec *vecs,
size_t vecCount, ancillary_data_container *ancillaryData,

View File

@ -374,6 +374,7 @@ net_protocol_module_info sICMPModule = {
icmp_error_reply,
NULL, // add_ancillary_data()
NULL, // process_ancillary_data()
NULL, // process_ancillary_data_no_container()
NULL, // send_data_no_buffer()
NULL // read_data_no_buffer()
};

View File

@ -166,12 +166,14 @@ struct ipv4_protocol : net_protocol {
uint8 time_to_live;
uint8 multicast_time_to_live;
uint32 flags;
struct sockaddr* interface_address; // for IP_MULTICAST_IF
IPv4MulticastFilter multicast_filter;
};
// protocol flags
#define IP_FLAG_HEADER_INCLUDED 0x01
#define IP_FLAG_HEADER_INCLUDED 0x01
#define IP_FLAG_RECEIVE_DEST_ADDR 0x02
static const int kDefaultTTL = 254;
@ -214,7 +216,8 @@ print_address(const in_addr* address, char* buf, size_t bufLen)
RawSocket::RawSocket(net_socket* socket)
: DatagramSocket<>("ipv4 raw socket", socket)
:
DatagramSocket<>("ipv4 raw socket", socket)
{
}
@ -1013,6 +1016,7 @@ ipv4_init_protocol(net_socket* socket)
protocol->time_to_live = kDefaultTTL;
protocol->multicast_time_to_live = kDefaultMulticastTTL;
protocol->flags = 0;
protocol->interface_address = NULL;
return protocol;
}
@ -1023,6 +1027,7 @@ ipv4_uninit_protocol(net_protocol* _protocol)
ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
delete protocol->raw;
delete protocol->interface_address;
delete protocol;
return B_OK;
}
@ -1118,6 +1123,10 @@ ipv4_getsockopt(net_protocol* _protocol, int level, int option, void* value,
return get_int_option(value, *_length,
(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
}
if (option == IP_RECVDSTADDR) {
return get_int_option(value, *_length,
(protocol->flags & IP_FLAG_RECEIVE_DEST_ADDR) != 0);
}
if (option == IP_TTL)
return get_int_option(value, *_length, protocol->time_to_live);
if (option == IP_TOS)
@ -1175,10 +1184,59 @@ ipv4_setsockopt(net_protocol* _protocol, int level, int option,
return B_OK;
}
if (option == IP_RECVDSTADDR) {
int getAddress;
if (length != sizeof(int))
return B_BAD_VALUE;
if (user_memcpy(&getAddress, value, sizeof(int)) != B_OK)
return B_BAD_ADDRESS;
if (getAddress && (protocol->socket->type == SOCK_DGRAM
|| protocol->socket->type == SOCK_RAW))
protocol->flags |= IP_FLAG_RECEIVE_DEST_ADDR;
else
protocol->flags &= ~IP_FLAG_RECEIVE_DEST_ADDR;
return B_OK;
}
if (option == IP_TTL)
return set_int_option(protocol->time_to_live, value, length);
if (option == IP_TOS)
return set_int_option(protocol->service_type, value, length);
if (option == IP_MULTICAST_IF) {
if (length != sizeof(struct in_addr))
return B_BAD_VALUE;
struct sockaddr_in* address = new (std::nothrow) sockaddr_in;
if (address == NULL)
return B_NO_MEMORY;
if (user_memcpy(&address->sin_addr, value, sizeof(struct in_addr))
!= B_OK) {
delete address;
return B_BAD_ADDRESS;
}
// Using INADDR_ANY to remove the previous setting.
if (address->sin_addr.s_addr == htonl(INADDR_ANY)) {
delete address;
delete protocol->interface_address;
protocol->interface_address = NULL;
return B_OK;
}
struct net_interface* interface
= sDatalinkModule->get_interface_with_address(sDomain,
(struct sockaddr*)address);
if (interface == NULL) {
delete address;
return EADDRNOTAVAIL;
}
delete protocol->interface_address;
protocol->interface_address = (struct sockaddr*)address;
return B_OK;
}
if (option == IP_MULTICAST_TTL) {
return set_int_option(protocol->multicast_time_to_live, value,
length);
@ -1405,6 +1463,25 @@ ipv4_send_data(net_protocol* _protocol, net_buffer* buffer)
offsetof(ipv4_header, destination)>(buffer));
}
// handle IP_MULTICAST_IF
if (IN_MULTICAST(ntohl(((sockaddr_in*)buffer->destination)->
sin_addr.s_addr)) && protocol->interface_address != NULL) {
net_interface* interface
= sDatalinkModule->get_interface_with_address(sDomain,
protocol->interface_address);
if (interface == NULL || (interface->flags & IFF_UP) == 0)
return EADDRNOTAVAIL;
buffer->interface = interface;
net_route* route = sDatalinkModule->get_route(sDomain,
interface->address);
if (route == NULL)
return ENETUNREACH;
return sDatalinkModule->send_data(route, buffer);
}
return sDatalinkModule->send_datagram(protocol, sDomain, buffer);
}
@ -1600,6 +1677,32 @@ ipv4_error_reply(net_protocol* protocol, net_buffer* causedError, uint32 code,
}
ssize_t
ipv4_process_ancillary_data_no_container(net_protocol* protocol,
net_buffer* buffer, void* msgControl, size_t msgControlLen)
{
ssize_t bytesWritten = 0;
if ((((ipv4_protocol*)protocol)->flags & IP_FLAG_RECEIVE_DEST_ADDR) != 0) {
if (msgControlLen < CMSG_SPACE(sizeof(struct in_addr)))
return B_NO_MEMORY;
cmsghdr* messageHeader = (cmsghdr*)msgControl;
messageHeader->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
messageHeader->cmsg_level = IPPROTO_IP;
messageHeader->cmsg_type = IP_RECVDSTADDR;
memcpy(CMSG_DATA(messageHeader),
&((struct sockaddr_in*)buffer->destination)->sin_addr,
sizeof(struct in_addr));
bytesWritten += CMSG_SPACE(sizeof(struct in_addr));
}
return bytesWritten;
}
// #pragma mark -
@ -1741,6 +1844,7 @@ net_protocol_module_info gIPv4Module = {
ipv4_error_reply,
NULL, // add_ancillary_data()
NULL, // process_ancillary_data()
ipv4_process_ancillary_data_no_container,
NULL, // send_data_no_buffer()
NULL // read_data_no_buffer()
};

View File

@ -383,6 +383,7 @@ net_protocol_module_info gL2CAPModule = {
l2cap_error_reply,
NULL, // add_ancillary_data()
NULL, // process_ancillary_data()
NULL, // process_ancillary_data_no_container()
NULL, // send_data_no_buffer()
NULL // read_data_no_buffer()
};

View File

@ -846,6 +846,7 @@ net_protocol_module_info sTCPModule = {
tcp_error_reply,
NULL, // add_ancillary_data()
NULL, // process_ancillary_data()
NULL, // process_ancillary_data_no_container()
NULL, // send_data_no_buffer()
NULL // read_data_no_buffer()
};

View File

@ -1146,6 +1146,15 @@ udp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
}
ssize_t
udp_process_ancillary_data_no_container(net_protocol *protocol,
net_buffer* buffer, void *data, size_t dataSize)
{
return protocol->next->module->process_ancillary_data_no_container(
protocol, buffer, data, dataSize);
}
// #pragma mark - module interface
@ -1256,6 +1265,7 @@ net_protocol_module_info sUDPModule = {
udp_error_reply,
NULL, // add_ancillary_data()
NULL, // process_ancillary_data()
udp_process_ancillary_data_no_container,
NULL, // send_data_no_buffer()
NULL // read_data_no_buffer()
};

View File

@ -508,6 +508,7 @@ net_protocol_module_info gUnixModule = {
unix_error_reply,
unix_add_ancillary_data,
unix_process_ancillary_data,
NULL,
unix_send_data_no_buffer,
unix_read_data_no_buffer
};

View File

@ -255,6 +255,32 @@ process_ancillary_data(net_socket* socket, ancillary_data_container* container,
}
static status_t
process_ancillary_data(net_socket* socket,
net_buffer* buffer, msghdr* messageHeader)
{
void *dataBuffer = messageHeader->msg_control;
ssize_t bytesWritten;
if (dataBuffer == NULL) {
messageHeader->msg_controllen = 0;
return B_OK;
}
if (socket->first_info->process_ancillary_data_no_container == NULL)
return EOPNOTSUPP;
bytesWritten = socket->first_info->process_ancillary_data_no_container(
socket->first_protocol, buffer, dataBuffer,
messageHeader->msg_controllen);
if (bytesWritten < 0)
return bytesWritten;
messageHeader->msg_controllen = bytesWritten;
return B_OK;
}
static ssize_t
socket_receive_no_buffer(net_socket* socket, msghdr* header, void* data,
size_t length, int flags)
@ -1171,8 +1197,12 @@ socket_receive(net_socket* socket, msghdr* header, void* data, size_t length,
// process ancillary data
if (header != NULL) {
if (buffer != NULL && header->msg_control != NULL) {
status = process_ancillary_data(socket,
gNetBufferModule.get_ancillary_data(buffer), header);
ancillary_data_container* container
= gNetBufferModule.get_ancillary_data(buffer);
if (container != NULL)
status = process_ancillary_data(socket, container, header);
else
status = process_ancillary_data(socket, buffer, header);
if (status != B_OK) {
gNetBufferModule.free(buffer);
return status;