From 5193237f1f52684a7f2c3dd5db552e65d2ca2943 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Wed, 15 Apr 2009 15:37:50 +0000 Subject: [PATCH] fixing #3712: * Since r30000, a net_socket is not zeroed anymore, which in turn leaves its two addresses (local and peer) in an uninitialized, but correct state - marking their state with ss_len == 0. However, this state was not properly detected in some ipv4-address functions, especially not the one that creates a hash value from those two addresses. This basically caused UDP to stop working, as here the peer address (as opposed to TCP) is usually not explicitly initialized. Adjusting the ipv4-address functions accordingly fixes the problem, such that DHCP (and the rest of UDP) should now work again. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30175 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/ipv4/ipv4_address.cpp | 72 ++++++++++++------- 1 file changed, 47 insertions(+), 25 deletions(-) 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 7ed7956079..164e54ea22 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp @@ -26,10 +26,12 @@ that is put into \a to. If \a replaceWithZeros is set \a from will be replaced by an empty address. - If a \a mask is given it is applied to \a from (such that \a to is the + If a \a mask is given it is applied to \a from (such that \a to is the result of \a from & \a mask). \return B_OK if the address could be copied \return B_NO_MEMORY if the new address could not be allocated + \return B_BAD_VALUE if any of \a from or \a mask refers to an uninitialized + address \return B_MISMATCHED_VALUES if \a address does not match family AF_INET */ static status_t @@ -47,6 +49,8 @@ ipv4_copy_address(const sockaddr *from, sockaddr **to, } else { if (from == NULL) return B_OK; + if (from->sa_len == 0 || (mask != NULL && mask->sa_len == 0)) + return B_BAD_VALUE; if (from->sa_family != AF_INET) return B_MISMATCHED_VALUES; @@ -69,17 +73,19 @@ ipv4_copy_address(const sockaddr *from, sockaddr **to, Routing utility function: applies \a mask to given \a address and puts the resulting address into \a result. \return B_OK if the mask has been applied - \return B_BAD_VALUE if \a address or \a mask is NULL + \return B_BAD_VALUE if \a address is NULL or if any of \a address or \a mask + refers to an uninitialized address */ static status_t ipv4_mask_address(const sockaddr *address, const sockaddr *mask, sockaddr *result) { - if (address == NULL || result == NULL) + if (address == NULL || address->sa_len == 0 || result == NULL + || (mask != NULL && mask->sa_len == 0)) return B_BAD_VALUE; memcpy(result, address, sizeof(sockaddr_in)); if (mask != NULL) { - ((sockaddr_in *)result)->sin_addr.s_addr + ((sockaddr_in *)result)->sin_addr.s_addr &= ((sockaddr_in *)mask)->sin_addr.s_addr; } @@ -90,7 +96,7 @@ ipv4_mask_address(const sockaddr *address, const sockaddr *mask, sockaddr *resul /*! Checks if the given \a address is the empty address. By default, the port is checked, too, but you can avoid that by passing \a checkPort = false. - \return true if \a address is NULL, uninitialized or the empty address, + \return true if \a address is NULL, uninitialized or the empty address, false if not */ static bool @@ -136,9 +142,10 @@ ipv4_equal_ports(const sockaddr *a, const sockaddr *b) /*! - Compares the IP-addresses and ports of the two given address structures + Compares the IP-addresses and ports of the two given address structures \a a and \a b. - \return true if IP-addresses and ports of \a a and \a b are equal, false if not + \return true if IP-addresses and ports of \a a and \a b are equal, false if + not */ static bool ipv4_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b) @@ -156,12 +163,12 @@ ipv4_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b) /*! - Applies the given \a mask two \a a and \a b and then checks whether + Applies the given \a mask two \a a and \a b and then checks whether the masked addresses match. \return true if \a a matches \a b after masking both, false if not */ static bool -ipv4_equal_masked_addresses(const sockaddr *a, const sockaddr *b, +ipv4_equal_masked_addresses(const sockaddr *a, const sockaddr *b, const sockaddr *mask) { if (a == NULL && b == NULL) @@ -189,8 +196,8 @@ ipv4_equal_masked_addresses(const sockaddr *a, const sockaddr *b, /*! Routing utility function: determines the least significant bit that is set - in the given \a mask. - \return the number of the first bit that is set (0-32, where 32 means + in the given \a mask. + \return the number of the first bit that is set (0-32, where 32 means that there's no bit set in the mask). */ static int32 @@ -226,7 +233,7 @@ ipv4_check_mask(const sockaddr *_mask) uint32 mask = ntohl(((const sockaddr_in *)_mask)->sin_addr.s_addr); - // A mask (from LSB) starts with zeros, after the first one, only ones + // A mask (from LSB) starts with zeros, after the first one, only ones // are allowed: bool zero = true; int8 bit = 0; @@ -243,7 +250,7 @@ ipv4_check_mask(const sockaddr *_mask) /*! Creates a buffer for the given \a address and prints the address into - it (hexadecimal representation in host byte order or ''). + it (hexadecimal representation in host byte order or ''). If \a printPort is set, the port is printed, too. \return B_OK if the address could be printed, \a buffer will point to the resulting string @@ -295,13 +302,13 @@ ipv4_print_address(const sockaddr *_address, char **_buffer, bool printPort) /*! - Determines the port of the given \a address. + Determines the port of the given \a address. \return uint16 representing the port-nr */ static uint16 ipv4_get_port(const sockaddr *address) { - if (address == NULL) + if (address == NULL || address->sa_len == 0) return 0; return ((sockaddr_in *)address)->sin_port; @@ -311,12 +318,12 @@ ipv4_get_port(const sockaddr *address) /*! Sets the port of the given \a address to \a port. \return B_OK if the port has been set - \return B_BAD_VALUE if \a address is NULL + \return B_BAD_VALUE if \a address is NULL or has not been initialized */ static status_t ipv4_set_port(sockaddr *address, uint16 port) { - if (address == NULL) + if (address == NULL || address->sa_len == 0) return B_BAD_VALUE; ((sockaddr_in *)address)->sin_port = port; @@ -327,13 +334,14 @@ ipv4_set_port(sockaddr *address, uint16 port) /*! Sets \a address to \a from. \return B_OK if \a from has been copied into \a address - \return B_BAD_VALUE if either \a address or \a from is NULL + \return B_BAD_VALUE if either \a address or \a from is NULL or if the + address given in from has not been initialized \return B_MISMATCHED_VALUES if from is not of family AF_INET */ static status_t ipv4_set_to(sockaddr *address, const sockaddr *from) { - if (address == NULL || from == NULL) + if (address == NULL || from == NULL || from->sa_len == 0) return B_BAD_VALUE; if (from->sa_family != AF_INET) @@ -345,13 +353,20 @@ ipv4_set_to(sockaddr *address, const sockaddr *from) } +/*! + Updates missing parts in \a address with the values in \a from. + \return B_OK if \a address has been updated from \a from + \return B_BAD_VALUE if either \a address or \a from is NULL or if the + address given in from has not been initialized + \return B_MISMATCHED_VALUES if from is not of family AF_INET +*/ static status_t ipv4_update_to(sockaddr *_address, const sockaddr *_from) { sockaddr_in *address = (sockaddr_in *)_address; const sockaddr_in *from = (const sockaddr_in *)_from; - if (address == NULL || from == NULL) + if (address == NULL || from == NULL || from->sin_len == 0) return B_BAD_VALUE; if (from->sin_family != AF_INET) @@ -438,7 +453,7 @@ ipv4_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast, /*! - Computes a hash-value of the given addresses \a ourAddress + Computes a hash-value of the given addresses \a ourAddress and \a peerAddress. \return uint32 representing the hash-value */ @@ -448,20 +463,27 @@ ipv4_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress) const sockaddr_in *our = (const sockaddr_in *)ourAddress; const sockaddr_in *peer = (const sockaddr_in *)peerAddress; - return ((our ? our->sin_port : 0) | ((peer ? peer->sin_port : 0) << 16)) - ^ (our ? our->sin_addr.s_addr : 0) ^ (peer ? peer->sin_addr.s_addr : 0); + bool haveOur = our && our->sin_len != 0; + bool havePeer = peer && peer->sin_len != 0; + + return + ((haveOur ? our->sin_port : 0) + | ((havePeer ? peer->sin_port : 0) << 16)) + ^ (haveOur ? our->sin_addr.s_addr : 0) + ^ (havePeer ? peer->sin_addr.s_addr : 0); } /*! Adds the given \a address to the IP-checksum \a checksum. \return B_OK if \a address has been added to the checksum - \return B_BAD_VALUE if either \a address or \a checksum is NULL + \return B_BAD_VALUE if either \a address or \a checksum is NULL or if + the given address is not initialized */ static status_t ipv4_checksum_address(struct Checksum *checksum, const sockaddr *address) { - if (checksum == NULL || address == NULL) + if (checksum == NULL || address == NULL || address->sa_len == 0) return B_BAD_VALUE; (*checksum) << (uint32)((sockaddr_in *)address)->sin_addr.s_addr;