* Added a set_to_defaults() function to the address module: it can be used

to retrieve the default settings for the netmask/broadcast depending on the
  specified address/netmask.
* interface_protocol_control() now uses this to reset the broadcast/netmask
  to their default values on SIOCSIFADDR resp. the former only on
  SIOCSIFNETMASK.
* This fixes bug #1861.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24170 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-02-28 15:43:27 +00:00
parent 487b83f327
commit b5a5aebc90
3 changed files with 99 additions and 21 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef NET_DATALINK_H
@ -67,7 +67,7 @@ struct net_datalink_module_info {
size_t *_length);
status_t (*send_data)(struct net_route *route, struct net_buffer *buffer);
status_t (*send_datagram)(struct net_protocol *protocol,
struct net_domain *domain, struct net_buffer *buffer);
struct net_domain *domain, struct net_buffer *buffer);
bool (*is_local_address)(struct net_domain *domain,
const struct sockaddr *address,
@ -75,7 +75,7 @@ struct net_datalink_module_info {
uint32 *_matchedType);
net_interface *(*get_interface)(struct net_domain *domain, uint32 index);
net_interface *(*get_interface_with_address)(struct net_domain *domain,
const struct sockaddr *address);
const struct sockaddr *address);
// routes
status_t (*add_route)(struct net_domain *domain,
@ -85,7 +85,7 @@ struct net_datalink_module_info {
struct net_route *(*get_route)(struct net_domain *domain,
const struct sockaddr *address);
status_t (*get_buffer_route)(struct net_domain *domain,
struct net_buffer *buffer, struct net_route **_route);
struct net_buffer *buffer, struct net_route **_route);
void (*put_route)(struct net_domain *domain, struct net_route *route);
status_t (*register_route_info)(struct net_domain *domain,
@ -100,7 +100,7 @@ struct net_address_module_info {
module_info info;
status_t (*copy_address)(const sockaddr *from, sockaddr **to,
bool replaceWithZeros /* = false */, const sockaddr *mask /* = NULL*/);
bool replaceWithZeros, const sockaddr *mask);
status_t (*mask_address)(const sockaddr *address, const sockaddr *mask,
sockaddr *result);
@ -110,7 +110,7 @@ struct net_address_module_info {
bool (*equal_addresses_and_ports)(const sockaddr *a, const sockaddr *b);
bool (*equal_masked_addresses)(const sockaddr *a, const sockaddr *b,
const sockaddr *mask);
bool (*is_empty_address)(const sockaddr *address, bool checkPort /* = true */);
bool (*is_empty_address)(const sockaddr *address, bool checkPort);
int32 (*first_mask_bit)(const sockaddr *mask);
@ -126,6 +126,9 @@ struct net_address_module_info {
status_t (*set_to)(sockaddr *address, const sockaddr *from);
status_t (*set_to_empty_address)(sockaddr *address);
status_t (*set_to_defaults)(sockaddr *defaultMask,
sockaddr *defaultBroadcast, sockaddr *address,
sockaddr *netmask);
status_t (*update_to)(sockaddr *address, const sockaddr *from);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -388,6 +388,55 @@ ipv4_set_to_empty_address(sockaddr *address)
}
static status_t
ipv4_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast,
sockaddr *_address, sockaddr *_mask)
{
sockaddr_in *defaultMask = (sockaddr_in *)_defaultMask;
sockaddr_in *defaultBroadcast = (sockaddr_in *)_defaultBroadcast;
sockaddr_in *address = (sockaddr_in *)_address;
sockaddr_in *mask = (sockaddr_in *)_mask;
if (address == NULL || (defaultMask == NULL && defaultBroadcast == NULL))
return B_BAD_VALUE;
in_addr_t net;
if (mask == NULL) {
// choose default netmask depending on the class of the address
net = address->sin_addr.s_addr;
if (IN_CLASSA(net)
|| (ntohl(net) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
// class A, or loopback
net = IN_CLASSA_NET;
} else if (IN_CLASSB(net)) {
// class B
net = IN_CLASSB_NET;
} else {
// class C and rest
net = IN_CLASSC_NET;
}
} else
net = mask->sin_addr.s_addr;
if (defaultMask != NULL) {
defaultMask->sin_len = sizeof(sockaddr_in);
defaultMask->sin_family = AF_INET;
defaultMask->sin_port = 0;
defaultMask->sin_addr.s_addr = net;
}
if (defaultBroadcast != NULL) {
defaultBroadcast->sin_len = sizeof(sockaddr_in);
defaultBroadcast->sin_family = AF_INET;
defaultBroadcast->sin_port = 0;
defaultBroadcast->sin_addr.s_addr = (address->sin_addr.s_addr & net)
| ~net;
}
return B_OK;
}
/*!
Computes a hash-value of the given addresses \a ourAddress
and \a peerAddress.
@ -441,6 +490,7 @@ net_address_module_info gIPv4AddressModule = {
ipv4_set_port,
ipv4_set_to,
ipv4_set_to_empty_address,
ipv4_set_to_defaults,
ipv4_update_to,
ipv4_hash_address_pair,
ipv4_checksum_address,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -164,6 +164,26 @@ add_default_routes(net_interface_private *interface, int32 option)
}
sockaddr *
reallocate_address(sockaddr **_address, uint32 size)
{
sockaddr *address = *_address;
size = max_c(size, sizeof(struct sockaddr));
if (address != NULL && address->sa_len >= size)
return address;
address = (sockaddr *)malloc(size);
if (address == NULL)
return NULL;
free(*_address);
*_address = address;
return address;
}
static status_t
datalink_control_interface(net_domain_private *domain, int32 option,
void *value, size_t *_length, size_t expected, bool getByName)
@ -624,27 +644,32 @@ interface_protocol_control(net_datalink_protocol *_protocol,
if (_address == NULL)
return B_BAD_VALUE;
sockaddr *address = *_address;
sockaddr *original = address;
// allocate new address if needed
if (address == NULL
|| (address->sa_len < request.ifr_addr.sa_len
&& request.ifr_addr.sa_len > sizeof(struct sockaddr))) {
address = (sockaddr *)malloc(
max_c(request.ifr_addr.sa_len, sizeof(struct sockaddr)));
}
sockaddr *address = reallocate_address(_address,
request.ifr_addr.sa_len);
// copy new address over
if (address != NULL) {
remove_default_routes(interface, option);
memcpy(address, &request.ifr_addr, request.ifr_addr.sa_len);
if (original != address) {
free(original);
*_address = address;
if (option == SIOCSIFADDR || option == SIOCSIFNETMASK) {
// reset netmask and broadcast addresses to defaults
sockaddr *netmask = NULL;
sockaddr *oldNetmask = NULL;
if (option == SIOCSIFADDR) {
netmask = reallocate_address(&interface->mask,
request.ifr_addr.sa_len);
} else
oldNetmask = address;
sockaddr *broadcast = reallocate_address(
&interface->destination, request.ifr_addr.sa_len);
interface->domain->address_module->set_to_defaults(
netmask, broadcast, interface->address, oldNetmask);
}
memcpy(address, &request.ifr_addr, request.ifr_addr.sa_len);
add_default_routes(interface, option);
}