net/udp: fix the invaild udp destination address
If the udp socket not connected, it is possible to have multi-different destination address in each iob entry, update the remote address every time to avoid sent to the incorrect destination. Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
parent
26c7ec5087
commit
b10dcf7c0d
@ -133,7 +133,7 @@ int psock_fstat(FAR struct socket *psock, FAR struct stat *buf)
|
||||
* order to get the MTU and LL_HDRLEN:
|
||||
*/
|
||||
|
||||
dev = udp_find_raddr_device(conn);
|
||||
dev = udp_find_raddr_device(conn, NULL);
|
||||
if (dev == NULL)
|
||||
{
|
||||
/* This should never happen except perhaps in some rare race
|
||||
|
@ -246,6 +246,22 @@ FAR struct udp_conn_s *udp_active(FAR struct net_driver_s *dev,
|
||||
|
||||
FAR struct udp_conn_s *udp_nextconn(FAR struct udp_conn_s *conn);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_select_port
|
||||
*
|
||||
* Description:
|
||||
* Select an unused port number.
|
||||
*
|
||||
* NOTE that in principle this function could fail if there is no available
|
||||
* port number. There is no check for that case and it would actually
|
||||
* in an infinite loop if that were the case. In this simple, small UDP
|
||||
* implementation, it is reasonable to assume that that error cannot happen
|
||||
* and that a port number will always be available.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_bind
|
||||
*
|
||||
@ -610,7 +626,9 @@ FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn);
|
||||
FAR struct net_driver_s *
|
||||
udp_find_raddr_device(FAR struct udp_conn_s *conn,
|
||||
FAR struct sockaddr_storage *remote);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_callback
|
||||
|
@ -172,76 +172,6 @@ static FAR struct udp_conn_s *udp_find_conn(uint8_t domain,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_select_port
|
||||
*
|
||||
* Description:
|
||||
* Select an unused port number.
|
||||
*
|
||||
* NOTE that in principle this function could fail if there is no available
|
||||
* port number. There is no check for that case and it would actually
|
||||
* in an infinite loop if that were the case. In this simple, small UDP
|
||||
* implementation, it is reasonable to assume that that error cannot happen
|
||||
* and that a port number will always be available.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Next available port number
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u)
|
||||
{
|
||||
static uint16_t g_last_udp_port;
|
||||
uint16_t portno;
|
||||
|
||||
net_lock();
|
||||
|
||||
/* Generate port base dynamically */
|
||||
|
||||
if (g_last_udp_port == 0)
|
||||
{
|
||||
g_last_udp_port = clock_systime_ticks() % 32000;
|
||||
|
||||
if (g_last_udp_port < 4096)
|
||||
{
|
||||
g_last_udp_port += 4096;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find an unused local port number. Loop until we find a valid
|
||||
* listen port number that is not being used by any other connection.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
/* Guess that the next available port number will be the one after
|
||||
* the last port number assigned.
|
||||
*/
|
||||
|
||||
++g_last_udp_port;
|
||||
|
||||
/* Make sure that the port number is within range */
|
||||
|
||||
if (g_last_udp_port >= 32000)
|
||||
{
|
||||
g_last_udp_port = 4096;
|
||||
}
|
||||
}
|
||||
while (udp_find_conn(domain, u, htons(g_last_udp_port)) != NULL);
|
||||
|
||||
/* Initialize and return the connection structure, bind it to the
|
||||
* port number
|
||||
*/
|
||||
|
||||
portno = g_last_udp_port;
|
||||
net_unlock();
|
||||
|
||||
return portno;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_ipv4_active
|
||||
*
|
||||
@ -527,6 +457,76 @@ static inline FAR struct udp_conn_s *
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_select_port
|
||||
*
|
||||
* Description:
|
||||
* Select an unused port number.
|
||||
*
|
||||
* NOTE that in principle this function could fail if there is no available
|
||||
* port number. There is no check for that case and it would actually
|
||||
* in an infinite loop if that were the case. In this simple, small UDP
|
||||
* implementation, it is reasonable to assume that that error cannot happen
|
||||
* and that a port number will always be available.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Next available port number
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u)
|
||||
{
|
||||
static uint16_t g_last_udp_port;
|
||||
uint16_t portno;
|
||||
|
||||
net_lock();
|
||||
|
||||
/* Generate port base dynamically */
|
||||
|
||||
if (g_last_udp_port == 0)
|
||||
{
|
||||
g_last_udp_port = clock_systime_ticks() % 32000;
|
||||
|
||||
if (g_last_udp_port < 4096)
|
||||
{
|
||||
g_last_udp_port += 4096;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find an unused local port number. Loop until we find a valid
|
||||
* listen port number that is not being used by any other connection.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
/* Guess that the next available port number will be the one after
|
||||
* the last port number assigned.
|
||||
*/
|
||||
|
||||
++g_last_udp_port;
|
||||
|
||||
/* Make sure that the port number is within range */
|
||||
|
||||
if (g_last_udp_port >= 32000)
|
||||
{
|
||||
g_last_udp_port = 4096;
|
||||
}
|
||||
}
|
||||
while (udp_find_conn(domain, u, htons(g_last_udp_port)) != NULL);
|
||||
|
||||
/* Initialize and return the connection structure, bind it to the
|
||||
* port number
|
||||
*/
|
||||
|
||||
portno = g_last_udp_port;
|
||||
net_unlock();
|
||||
|
||||
return portno;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: udp_initialize
|
||||
*
|
||||
|
@ -184,7 +184,9 @@ FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
|
||||
FAR struct net_driver_s *
|
||||
udp_find_raddr_device(FAR struct udp_conn_s *conn,
|
||||
FAR struct sockaddr_storage *remote)
|
||||
{
|
||||
/* We need to select the device that is going to route the UDP packet
|
||||
* based on the provided IP address.
|
||||
@ -195,13 +197,25 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
|
||||
if (conn->domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
in_addr_t raddr;
|
||||
|
||||
if (remote)
|
||||
{
|
||||
FAR const struct sockaddr_in *inaddr =
|
||||
(FAR const struct sockaddr_in *)remote;
|
||||
net_ipv4addr_copy(raddr, inaddr->sin_addr.s_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
net_ipv4addr_copy(raddr, conn->u.ipv4.raddr);
|
||||
}
|
||||
|
||||
/* Check if the remote, destination address is the broadcast
|
||||
* or multicast address. If this is the case, select the device
|
||||
* using the locally bound address (assuming that there is one).
|
||||
*/
|
||||
|
||||
if (conn->u.ipv4.raddr == INADDR_BROADCAST ||
|
||||
IN_MULTICAST(NTOHL(conn->u.ipv4.raddr)))
|
||||
if (raddr == INADDR_BROADCAST || IN_MULTICAST(NTOHL(raddr)))
|
||||
{
|
||||
/* Make sure that the socket is bound to some non-zero, local
|
||||
* address. Zero is used as an indication that the laddr is
|
||||
@ -225,12 +239,12 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
|
||||
* address.
|
||||
*/
|
||||
|
||||
else if (conn->u.ipv4.raddr != INADDR_ANY)
|
||||
else if (raddr != INADDR_ANY)
|
||||
{
|
||||
/* Normal lookup using the verified remote address */
|
||||
|
||||
return netdev_findby_ripv4addr(conn->u.ipv4.laddr,
|
||||
conn->u.ipv4.raddr);
|
||||
raddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -248,12 +262,25 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
net_ipv6addr_t raddr;
|
||||
|
||||
if (remote)
|
||||
{
|
||||
FAR const struct sockaddr_in6 *inaddr =
|
||||
(FAR const struct sockaddr_in6 *)remote;
|
||||
net_ipv6addr_copy(raddr, inaddr->sin6_addr.s6_addr16);
|
||||
}
|
||||
else
|
||||
{
|
||||
net_ipv6addr_copy(raddr, conn->u.ipv6.raddr);
|
||||
}
|
||||
|
||||
/* Check if the remote, destination address is a multicast
|
||||
* address. If this is the case, select the device
|
||||
* using the locally bound address (assuming that there is one).
|
||||
*/
|
||||
|
||||
if (net_is_addr_mcast(conn->u.ipv6.raddr))
|
||||
if (net_is_addr_mcast(raddr))
|
||||
{
|
||||
/* Make sure that the socket is bound to some non-zero, local
|
||||
* address. The IPv6 unspecified address is used as an
|
||||
@ -278,12 +305,12 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
|
||||
* address.
|
||||
*/
|
||||
|
||||
else if (!net_ipv6addr_cmp(conn->u.ipv6.raddr, g_ipv6_unspecaddr))
|
||||
else if (!net_ipv6addr_cmp(raddr, g_ipv6_unspecaddr))
|
||||
{
|
||||
/* Normal lookup using the verified remote address */
|
||||
|
||||
return netdev_findby_ripv6addr(conn->u.ipv6.laddr,
|
||||
conn->u.ipv6.raddr);
|
||||
raddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -279,7 +279,6 @@ static int sendto_next_transfer(FAR struct socket *psock,
|
||||
{
|
||||
FAR struct udp_wrbuffer_s *wrb;
|
||||
FAR struct net_driver_s *dev;
|
||||
int ret;
|
||||
|
||||
/* Set the UDP "connection" to the destination address of the write buffer
|
||||
* at the head of the queue.
|
||||
@ -292,11 +291,15 @@ static int sendto_next_transfer(FAR struct socket *psock,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = udp_connect(conn, (FAR const struct sockaddr *)&wrb->wb_dest);
|
||||
if (ret < 0)
|
||||
/* Has this address already been bound to a local port (lport)? */
|
||||
|
||||
if (!conn->lport)
|
||||
{
|
||||
nerr("ERROR: udp_connect failed: %d\n", ret);
|
||||
return ret;
|
||||
/* No.. Find an unused local port number and bind it to the
|
||||
* connection structure.
|
||||
*/
|
||||
|
||||
conn->lport = htons(udp_select_port(conn->domain, &conn->u));
|
||||
}
|
||||
|
||||
/* Get the device that will handle the remote packet transfers. This
|
||||
@ -308,7 +311,7 @@ static int sendto_next_transfer(FAR struct socket *psock,
|
||||
* transmission could harm performance.
|
||||
*/
|
||||
|
||||
dev = udp_find_raddr_device(conn);
|
||||
dev = udp_find_raddr_device(conn, &wrb->wb_dest);
|
||||
if (dev == NULL)
|
||||
{
|
||||
nerr("ERROR: udp_find_raddr_device failed\n");
|
||||
@ -453,6 +456,14 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
|
||||
wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||
DEBUGASSERT(wrb != NULL);
|
||||
|
||||
/* If the udp socket not connected, it is possible to have
|
||||
* multi-different destination address in each iob entry,
|
||||
* update the remote address every time to avoid sent to the
|
||||
* incorrect destination.
|
||||
*/
|
||||
|
||||
udp_connect(conn, (FAR const struct sockaddr *)&wrb->wb_dest);
|
||||
|
||||
/* Get the amount of data that we can send in the next packet.
|
||||
* We will send either the remaining data in the buffer I/O
|
||||
* buffer chain, or as much as will fit given the MSS and current
|
||||
|
@ -431,7 +431,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
|
||||
* should never be NULL.
|
||||
*/
|
||||
|
||||
state.st_dev = udp_find_raddr_device(conn);
|
||||
state.st_dev = udp_find_raddr_device(conn, NULL);
|
||||
if (state.st_dev == NULL)
|
||||
{
|
||||
nerr("ERROR: udp_find_raddr_device failed\n");
|
||||
|
Loading…
x
Reference in New Issue
Block a user