diff --git a/headers/private/net/net_datalink.h b/headers/private/net/net_datalink.h index 12dfef514b..196bed4611 100644 --- a/headers/private/net/net_datalink.h +++ b/headers/private/net/net_datalink.h @@ -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); diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp index ca07a517b8..7ed7956079 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp @@ -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, diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index 1402236c8b..140dd3efad 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -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); }