diff --git a/net/inet/inet_recvfrom.c b/net/inet/inet_recvfrom.c index 5940ca2deb..e35fefe602 100644 --- a/net/inet/inet_recvfrom.c +++ b/net/inet/inet_recvfrom.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/inet/inet_recvfrom.c * - * Copyright (C) 2007-2009, 2011-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -1206,27 +1206,9 @@ static ssize_t inet_udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t net_lock(); inet_recvfrom_initialize(psock, buf, len, from, fromlen, &state); - /* If the UDP socket was previously assigned a remote peer address via - * connect(), then it is not necessary to use recvfrom() to obtain the - * address of the remote peer: UDP messages will be received only from - * the connected peer. Normally recv() would be used with such connected - * UDP sockets. - */ - - if (!_SS_ISCONNECTED(psock->s_flags)) - { - /* Setup the UDP remote connection to accept packets from any remote - * address. - */ - - ret = udp_connect(conn, NULL); - if (ret < 0) - { - goto errout_with_state; - } - } - #ifdef CONFIG_NET_UDP_READAHEAD + /* Copy the read-ahead data from the packet */ + inet_udp_readahead(&state); /* The default return value is the number of bytes that we just copied @@ -1246,6 +1228,8 @@ static ssize_t inet_udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t #endif #ifdef CONFIG_NET_UDP_READAHEAD + /* Handle non-blocking UDP sockets */ + if (_SS_ISNONBLOCK(psock->s_flags)) { /* Return the number of bytes read from the read-ahead buffer if diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c index 4409680fd9..8240e569d5 100644 --- a/net/inet/inet_sockif.c +++ b/net/inet/inet_sockif.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/inet/inet_sockif.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -695,6 +695,7 @@ static int inet_connect(FAR struct socket *psock, #if defined(CONFIG_NET_UDP) && defined(NET_UDP_HAVE_STACK) case SOCK_DGRAM: { + FAR struct udp_conn_s *conn; int ret; /* We will accept connecting to a addr == NULL for disconnection. @@ -709,18 +710,21 @@ static int inet_connect(FAR struct socket *psock, /* Perform the connect/disconnect operation */ - ret = udp_connect(psock->s_conn, addr); + conn = (FAR struct udp_conn_s *)psock->s_conn; + ret = udp_connect(conn, addr); if (ret < 0 || addr == NULL) { /* Failed to connect or explicitly disconnected */ psock->s_flags &= ~_SF_CONNECTED; + conn->flags &= ~_UDP_FLAG_CONNECTMODE; } else { /* Successfully connected */ psock->s_flags |= _SF_CONNECTED; + conn->flags |= _UDP_FLAG_CONNECTMODE; } return ret; diff --git a/net/udp/udp.h b/net/udp/udp.h index 8e317ec820..ec4c3be190 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -86,6 +86,12 @@ #define udp_callback_free(dev,conn,cb) \ devif_conn_callback_free((dev), (cb), &(conn)->list) +/* Definitions for the UDP connection struct flag field */ + +#define _UDP_FLAG_CONNECTMODE (1 << 0) /* Bit 0: UDP connection-mode */ + +#define _UDP_ISCONNECTMODE(f) (((f) & _UDP_FLAG_CONNECTMODE) != 0) + /**************************************************************************** * Public Type Definitions ****************************************************************************/ @@ -101,6 +107,7 @@ struct udp_conn_s union ip_binding_u u; /* IP address binding */ uint16_t lport; /* Bound local port number (network byte order) */ uint16_t rport; /* Remote port number (network byte order) */ + uint8_t flags; /* See _UDP_FLAG_* definitions */ uint8_t domain; /* IP domain: PF_INET or PF_INET6 */ uint8_t ttl; /* Default time-to-live */ uint8_t crefs; /* Reference counts on this instance */ diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c index 2ea1c4e7a5..0e12fceebe 100644 --- a/net/udp/udp_conn.c +++ b/net/udp/udp_conn.c @@ -272,35 +272,56 @@ static inline FAR struct udp_conn_s * /* If the local UDP port is non-zero, the connection is considered * to be used. If so, then the following checks are performed: * - * - The local port number is checked against the destination port - * number in the received packet. - * - The remote port number is checked if the connection is bound - * to a remote port. - * - If multiple network interfaces are supported, then the local - * IP address is available and we will insist that the - * destination IP matches the bound address (or the destination - * IP address is a broadcast address). If a socket is bound to - * INADDRY_ANY (laddr), then it should receive all packets - * directed to the port. - * - Finally, if the connection is bound to a remote IP address, - * the source IP address of the packet is checked. Broadcast - * addresses are also accepted. + * 1. The destination address is verified against the bound address + * of the connection. + * + * - The local port number is checked against the destination port + * number in the received packet. + * - If multiple network interfaces are supported, then the local + * IP address is available and we will insist that the + * destination IP matches the bound address (or the destination + * IP address is a broadcast address). If a socket is bound to + * INADDRY_ANY (laddr), then it should receive all packets + * directed to the port. + * + * 2. If this is a connection mode UDP socket, then the source address + * is verified against the connected remote address. + * + * - The remote port number is checked if the connection is bound + * to a remote port. + * - Finally, if the connection is bound to a remote IP address, + * the source IP address of the packet is checked. Broadcast + * addresses are also accepted. * * If all of the above are true then the newly received UDP packet * is destined for this UDP connection. * - * To send and receive broadcast packets, the application should: + * To send and receive multicast packets, the application should: * - * - Bind socket to INADDR_ANY - * - setsockopt to SO_BROADCAST - * - call sendto with sendaddr.sin_addr.s_addr = - * - call recvfrom. + * - Bind socket to INADDR6_ANY (for the all-nodes multicast address) + * or to a specific + * - setsockopt to SO_BROADCAST (for all-nodes address) + * + * For connection-less UDP sockets: + * + * - call sendto with sendaddr.sin_addr.s_addr = + * - call recvfrom. + * + * For connection-mode UDP sockets: + * + * - call connect() to connect the UDP socket to a specific remote + * address, then + * - Call send() with no address address information + * - call recv() (from address information should not be needed) * * REVIST: SO_BROADCAST flag is currently ignored. */ + /* Check that there is a local port number and this is matches + * the port number in the destination address. + */ + if (conn->lport != 0 && udp->destport == conn->lport && - (conn->rport == 0 || udp->srcport == conn->rport) && /* Local port accepts any address on this port or there * is an exact match in destipaddr and the bound local @@ -309,22 +330,53 @@ static inline FAR struct udp_conn_s * */ (net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY) || - net_ipv4addr_hdrcmp(ip->destipaddr, &conn->u.ipv4.laddr)) && - - /* If not connected to a remote address, or a broadcast address - * destipaddr was received, or there is an exact match between the - * srcipaddr and the bound IP address, then accept the packet. + net_ipv4addr_hdrcmp(ip->destipaddr, &conn->u.ipv4.laddr))) + { + /* Check if the socket is connection mode. In this case, only + * packets with source addresses from the connected remote peer + * will be accepted. */ - (net_ipv4addr_cmp(conn->u.ipv4.raddr, INADDR_ANY) || -#ifdef CONFIG_NET_BROADCAST - net_ipv4addr_hdrcmp(ip->destipaddr, &bcast) || -#endif - net_ipv4addr_hdrcmp(ip->srcipaddr, &conn->u.ipv4.raddr))) - { - /* Matching connection found.. return a reference to it */ + if (_UDP_ISCONNECTMODE(conn->flags)) + { + /* Check if the UDP connection is either (1) accepting packets + * from any port or (2) the packet srcport matches the local + * bound port number. + */ - break; + if ((conn->rport == 0 || udp->srcport == conn->rport) && + + /* If (1) not connected to a remote address, or (2) a all- + * nodes multicast destipaddr was received, or (3) there is an + * exact match between the srcipaddr and the bound remote IP + * address, then accept the packet. + */ + + + + (net_ipv4addr_cmp(conn->u.ipv4.raddr, INADDR_ANY) || +#ifdef CONFIG_NET_BROADCAST + net_ipv4addr_hdrcmp(ip->destipaddr, &bcast) || +#endif + net_ipv4addr_hdrcmp(ip->srcipaddr, &conn->u.ipv4.raddr))) + { + /* Matching connection found.. Break out of the loop and + * return this reference to it. + */ + + break; + } + } + else + { + /* This UDP socket is not connected. We need to match only + * the destination address with the bound socket address. + * Break out out of the loop and return this reference to + * the matching connection structure. + */ + + break; + } } /* Look at the next active connection */ @@ -356,64 +408,112 @@ static inline FAR struct udp_conn_s * FAR struct udp_conn_s *conn; conn = (FAR struct udp_conn_s *)g_active_udp_connections.head; - while (conn) + while (conn != NULL) { /* If the local UDP port is non-zero, the connection is considered * to be used. If so, then the following checks are performed: * - * - The local port number is checked against the destination port - * number in the received packet. - * - The remote port number is checked if the connection is bound - * to a remote port. - * - If multiple network interfaces are supported, then the local - * IP address is available and we will insist that the - * destination IP matches the bound address. If a socket is bound to - * INADDR6_ANY (laddr), then it should receive all packets directed - * to the port. REVISIT: Should also depend on SO_BROADCAST. - * - Finally, if the connection is bound to a remote IP address, - * the source IP address of the packet is checked. + * 1. The destination address is verified against the bound address + * of the connection. + * + * - The local port number is checked against the destination port + * number in the received packet. + * - If multiple network interfaces are supported, then the local + * IP address is available and we will insist that the + * destination IP matches the bound address. If a socket is bound + * to INADDR6_ANY (laddr), then it should receive all packets + * directed to the port. REVISIT: Should also depend on SO_BROADCAST. + * + * 2. If this is a connection mode UDP socket, then the source address + * is verified against the connected remote address. + * + * - The remote port number is checked if the connection is bound + * to a remote port. + * - Finally, if the connection is bound to a remote IP address, + * the source IP address of the packet is checked. * * If all of the above are true then the newly received UDP packet * is destined for this UDP connection. * * To send and receive multicast packets, the application should: * - * - Bind socket to INADDR6_ANY (for the all-nodes multicast address) - * or to a specific - * - setsockopt to SO_BROADCAST (for all-nodes address) - * - call sendto with sendaddr.sin_addr.s_addr = - * - call recvfrom. + * - Bind socket to INADDR6_ANY (for the all-nodes multicast address) + * or to a specific + * - setsockopt to SO_BROADCAST (for all-nodes address) + * + * For connection-less UDP sockets: + * + * - call sendto with sendaddr.sin_addr.s_addr = + * - call recvfrom. + * + * For connection-mode UDP sockets: + * + * - call connect() to connect the UDP socket to a specific remote + * address, then + * - Call send() with no address address information + * - call recv() (from address information should not be needed) * * REVIST: SO_BROADCAST flag is currently ignored. */ - if (conn->lport != 0 && udp->destport == conn->lport && - (conn->rport == 0 || udp->srcport == conn->rport) && + /* Check that there is a local port number and this is matches + * the port number in the destination address. + */ - /* Local port accepts any address on this port or there - * is an exact match in destipaddr and the bound local - * address. This catches the cast of the all nodes multicast - * when the socket is bound to INADDR6_ANY. + if ((conn->lport != 0 && udp->destport == conn->lport && + + /* Check if the local port accepts any address on this port or + * that there is an exact match between the destipaddr and the + * bound local address. This catches the case of the all nodes + * multicast when the socket is bound to INADDR6_ANY. */ (net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_allzeroaddr) || - net_ipv6addr_hdrcmp(ip->destipaddr, conn->u.ipv6.laddr)) && - - /* If not connected to a remote address, or a all-nodes multicast - * destipaddr was received, or there is an exact match between the - * srcipaddr and the bound remote IP address, then accept the - * packet. + net_ipv6addr_hdrcmp(ip->destipaddr, conn->u.ipv6.laddr)))) + { + /* Check if the socket is connection mode. In this case, only + * packets with source addresses from the connected remote peer + * will be accepted. */ - (net_ipv6addr_cmp(conn->u.ipv6.raddr, g_ipv6_allzeroaddr) || -#ifdef CONFIG_NET_BROADCAST - net_ipv6addr_hdrcmp(ip->destipaddr, g_ipv6_allnodes) || -#endif - net_ipv6addr_hdrcmp(ip->srcipaddr, conn->u.ipv6.raddr))) - { - /* Matching connection found.. return a reference to it */ + if (_UDP_ISCONNECTMODE(conn->flags)) + { + /* Check if the UDP connection is either (1) accepting packets + * from any port or (2) the packet srcport matches the local + * bound port number. + */ - break; + if ((conn->rport == 0 || udp->srcport == conn->rport) && + + /* If (1) not connected to a remote address, or (2) a all- + * nodes multicast destipaddr was received, or (3) there is an + * exact match between the srcipaddr and the bound remote IP + * address, then accept the packet. + */ + + (net_ipv6addr_cmp(conn->u.ipv6.raddr, g_ipv6_allzeroaddr) || +#ifdef CONFIG_NET_BROADCAST + net_ipv6addr_hdrcmp(ip->destipaddr, g_ipv6_allnodes) || +#endif + net_ipv6addr_hdrcmp(ip->srcipaddr, conn->u.ipv6.raddr))) + { + /* Matching connection found.. Break out of the loop and + * return this reference to it. + */ + + break; + } + } + else + { + /* This UDP socket is not connected. We need to match only + * the destination address with the bound socket address. + * Break out out of the loop and return this reference to + * the matching connection structure. + */ + + break; + } } /* Look at the next active connection */ diff --git a/net/udp/udp_finddev.c b/net/udp/udp_finddev.c index 8e2d014ea4..0f7b9d6cae 100644 --- a/net/udp/udp_finddev.c +++ b/net/udp/udp_finddev.c @@ -181,7 +181,7 @@ FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn) * remote IP address. * * Input Parameters: - * conn - UDP connection structure (not currently used). + * conn - UDP connection structure. * * Returned Value: * A pointer to the network driver to use. diff --git a/net/udp/udp_input.c b/net/udp/udp_input.c index 4043bd1488..3462c9a5d0 100644 --- a/net/udp/udp_input.c +++ b/net/udp/udp_input.c @@ -2,7 +2,7 @@ * net/udp/udp_input.c * Handling incoming UDP input * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: diff --git a/net/udp/udp_netpoll.c b/net/udp/udp_netpoll.c index 332de04aeb..8ff12d0ecf 100644 --- a/net/udp/udp_netpoll.c +++ b/net/udp/udp_netpoll.c @@ -198,24 +198,6 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) info->dev = udp_find_laddr_device(conn); - /* Check if the UDP socket was previously assigned a remote peer address - * via connect(). In that case, we will only be interested in poll - * related events associated with that address. - */ - - if (!_SS_ISCONNECTED(psock->s_flags)) - { - /* Setup the UDP remote connection to accept packets from any remote - * address. - */ - - ret = udp_connect(conn, NULL); - if (ret) - { - goto errout_with_lock; - } - } - /* Allocate a UDP callback structure */ cb = udp_callback_alloc(info->dev, conn);