* 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
This commit is contained in:
Oliver Tappe
2009-04-15 15:37:50 +00:00
parent 7cc93cd01c
commit 5193237f1f
@@ -26,10 +26,12 @@
that is put into \a to. that is put into \a to.
If \a replaceWithZeros is set \a from will be replaced by an empty If \a replaceWithZeros is set \a from will be replaced by an empty
address. 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). result of \a from & \a mask).
\return B_OK if the address could be copied \return B_OK if the address could be copied
\return B_NO_MEMORY if the new address could not be allocated \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 \return B_MISMATCHED_VALUES if \a address does not match family AF_INET
*/ */
static status_t static status_t
@@ -47,6 +49,8 @@ ipv4_copy_address(const sockaddr *from, sockaddr **to,
} else { } else {
if (from == NULL) if (from == NULL)
return B_OK; return B_OK;
if (from->sa_len == 0 || (mask != NULL && mask->sa_len == 0))
return B_BAD_VALUE;
if (from->sa_family != AF_INET) if (from->sa_family != AF_INET)
return B_MISMATCHED_VALUES; 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 Routing utility function: applies \a mask to given \a address and puts
the resulting address into \a result. the resulting address into \a result.
\return B_OK if the mask has been applied \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 static status_t
ipv4_mask_address(const sockaddr *address, const sockaddr *mask, sockaddr *result) 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; return B_BAD_VALUE;
memcpy(result, address, sizeof(sockaddr_in)); memcpy(result, address, sizeof(sockaddr_in));
if (mask != NULL) { if (mask != NULL) {
((sockaddr_in *)result)->sin_addr.s_addr ((sockaddr_in *)result)->sin_addr.s_addr
&= ((sockaddr_in *)mask)->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 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. 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 false if not
*/ */
static bool 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. \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 static bool
ipv4_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b) 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. the masked addresses match.
\return true if \a a matches \a b after masking both, false if not \return true if \a a matches \a b after masking both, false if not
*/ */
static bool 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) const sockaddr *mask)
{ {
if (a == NULL && b == NULL) 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 Routing utility function: determines the least significant bit that is set
in the given \a mask. in the given \a mask.
\return the number of the first bit that is set (0-32, where 32 means \return the number of the first bit that is set (0-32, where 32 means
that there's no bit set in the mask). that there's no bit set in the mask).
*/ */
static int32 static int32
@@ -226,7 +233,7 @@ ipv4_check_mask(const sockaddr *_mask)
uint32 mask = ntohl(((const sockaddr_in *)_mask)->sin_addr.s_addr); 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: // are allowed:
bool zero = true; bool zero = true;
int8 bit = 0; 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 Creates a buffer for the given \a address and prints the address into
it (hexadecimal representation in host byte order or '<none>'). it (hexadecimal representation in host byte order or '<none>').
If \a printPort is set, the port is printed, too. If \a printPort is set, the port is printed, too.
\return B_OK if the address could be printed, \a buffer will point to \return B_OK if the address could be printed, \a buffer will point to
the resulting string 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 \return uint16 representing the port-nr
*/ */
static uint16 static uint16
ipv4_get_port(const sockaddr *address) ipv4_get_port(const sockaddr *address)
{ {
if (address == NULL) if (address == NULL || address->sa_len == 0)
return 0; return 0;
return ((sockaddr_in *)address)->sin_port; 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. Sets the port of the given \a address to \a port.
\return B_OK if the port has been set \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 static status_t
ipv4_set_port(sockaddr *address, uint16 port) ipv4_set_port(sockaddr *address, uint16 port)
{ {
if (address == NULL) if (address == NULL || address->sa_len == 0)
return B_BAD_VALUE; return B_BAD_VALUE;
((sockaddr_in *)address)->sin_port = port; ((sockaddr_in *)address)->sin_port = port;
@@ -327,13 +334,14 @@ ipv4_set_port(sockaddr *address, uint16 port)
/*! /*!
Sets \a address to \a from. Sets \a address to \a from.
\return B_OK if \a from has been copied into \a address \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 \return B_MISMATCHED_VALUES if from is not of family AF_INET
*/ */
static status_t static status_t
ipv4_set_to(sockaddr *address, const sockaddr *from) 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; return B_BAD_VALUE;
if (from->sa_family != AF_INET) 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 static status_t
ipv4_update_to(sockaddr *_address, const sockaddr *_from) ipv4_update_to(sockaddr *_address, const sockaddr *_from)
{ {
sockaddr_in *address = (sockaddr_in *)_address; sockaddr_in *address = (sockaddr_in *)_address;
const sockaddr_in *from = (const sockaddr_in *)_from; 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; return B_BAD_VALUE;
if (from->sin_family != AF_INET) 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. and \a peerAddress.
\return uint32 representing the hash-value \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 *our = (const sockaddr_in *)ourAddress;
const sockaddr_in *peer = (const sockaddr_in *)peerAddress; const sockaddr_in *peer = (const sockaddr_in *)peerAddress;
return ((our ? our->sin_port : 0) | ((peer ? peer->sin_port : 0) << 16)) bool haveOur = our && our->sin_len != 0;
^ (our ? our->sin_addr.s_addr : 0) ^ (peer ? peer->sin_addr.s_addr : 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. 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_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 static status_t
ipv4_checksum_address(struct Checksum *checksum, const sockaddr *address) 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; return B_BAD_VALUE;
(*checksum) << (uint32)((sockaddr_in *)address)->sin_addr.s_addr; (*checksum) << (uint32)((sockaddr_in *)address)->sin_addr.s_addr;