7332d2decf
NuttX provides the UDP_BINDTODEVICE socket option. This is a UDP protocol-specific implementation of the semi-standard Linux SO_BINDTODEVICE socket option: "SO_BINDTODEVICE forces packets on the socket to only egress the bound interface, regardless of what the IP routing table would normally choose. Similarly only packets which ingress the bound interface will be received on the socket, packets from other interfaces will not be delivered to the socket." https://codingrelic.geekhold.com/2009/10/code-snippet-sobindtodevice.html If CONFIG_NET_UDP_BINDTODEVICE is selected and a UDP socket is bound to the device, then unrecognized packets UDP packets must not be dropped, but must be forwarded along to the bound socket unconditionally. It the typical case, this should have no impact. It does effect the applications that use DHCP and do select the UDP_BINDTODEVICE socket option. This PR replace existing improper logic in the code and also the improper attempts to fix problems from PR #3601 and PR #3598. Those changes are improper because they expose DHCP appliction dependencies in the OS, breaking modularity and independence of the OS and application. Tested with stm32f4discovery:netnsh with CONFIG_NET_UDP_BINDTODEVICE. A proper DHCP test setup is needed, however.
201 lines
6.3 KiB
C
201 lines
6.3 KiB
C
/****************************************************************************
|
|
* net/udp/udp_setsockopt.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <stdint.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include <debug.h>
|
|
|
|
#include <net/if.h>
|
|
#include <netinet/udp.h>
|
|
|
|
#include <nuttx/net/net.h>
|
|
#include <nuttx/net/netdev.h>
|
|
#include <nuttx/net/udp.h>
|
|
|
|
#include "socket/socket.h"
|
|
#include "utils/utils.h"
|
|
#include "netdev/netdev.h"
|
|
#include "udp/udp.h"
|
|
|
|
#ifdef CONFIG_NET_UDPPROTO_OPTIONS
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: udp_setsockopt
|
|
*
|
|
* Description:
|
|
* udp_setsockopt() sets the UDP-protocol option specified by the
|
|
* 'option' argument to the value pointed to by the 'value' argument for
|
|
* the socket specified by the 'psock' argument.
|
|
*
|
|
* See <netinet/udp.h> for the a complete list of values of UDP protocol
|
|
* options.
|
|
*
|
|
* Input Parameters:
|
|
* psock Socket structure of socket to operate on
|
|
* option identifies the option to set
|
|
* value Points to the argument value
|
|
* value_len The length of the argument value
|
|
*
|
|
* Returned Value:
|
|
* Returns zero (OK) on success. On failure, it returns a negated errno
|
|
* value to indicate the nature of the error. See psock_setcockopt() for
|
|
* the list of possible error values.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int udp_setsockopt(FAR struct socket *psock, int option,
|
|
FAR const void *value, socklen_t value_len)
|
|
{
|
|
#ifdef CONFIG_NET_UDP_BINDTODEVICE
|
|
/* Keep alive options are the only UDP protocol socket option currently
|
|
* supported.
|
|
*/
|
|
|
|
FAR struct udp_conn_s *conn;
|
|
int ret;
|
|
|
|
DEBUGASSERT(psock != NULL && value != NULL && psock->s_conn != NULL);
|
|
conn = (FAR struct udp_conn_s *)psock->s_conn;
|
|
|
|
/* All of the UDP protocol options apply only UDP sockets. The sockets
|
|
* do not have to be connected.. that might occur later with the KeepAlive
|
|
* already configured.
|
|
*/
|
|
|
|
if (psock->s_type != SOCK_DGRAM)
|
|
{
|
|
nerr("ERROR: Not a UDP socket\n");
|
|
return -ENOTCONN;
|
|
}
|
|
|
|
/* Handle the UDP-protocol options */
|
|
|
|
switch (option)
|
|
{
|
|
#ifdef CONFIG_NET_UDP_BINDTODEVICE
|
|
/* Handle the UDP_BINDTODEVICE socket-level option.
|
|
*
|
|
* NOTE: UDP_BINDTODEVICE is declared in linux as SO_BINDTODEVICE,
|
|
* but this option only makes sense for UDP sockets trying to broadcast
|
|
* while their local address is not set, eg, with DHCP requests.
|
|
* The problem is that we are not able to determine the interface to be
|
|
* used for sending packets when multiple interfaces do not have a
|
|
* local address yet. This option can be used to "force" the interface
|
|
* used to send the UDP traffic in this connection. Note that it does
|
|
* NOT only apply to broadcast packets.
|
|
*/
|
|
|
|
case UDP_BINDTODEVICE: /* Bind socket to a specific network device */
|
|
{
|
|
FAR struct net_driver_s *dev;
|
|
|
|
/* Check if we are are unbinding the socket */
|
|
|
|
if (value == NULL || value_len == 0 ||
|
|
(value_len > 0 && ((FAR char *)value)[0] == 0))
|
|
{
|
|
/* Just report success if the socket is not bound to an
|
|
* interface.
|
|
*/
|
|
|
|
if (conn->boundto != 0)
|
|
{
|
|
/* Get the interface that we are bound do. NULL would
|
|
* indicate that the interface no longer exists for some
|
|
* reason.
|
|
*/
|
|
|
|
dev = netdev_findbyindex(conn->boundto);
|
|
if (dev != NULL)
|
|
{
|
|
/* Clear the interface flag to unbind the device from
|
|
* the socket.
|
|
*/
|
|
|
|
IFF_CLR_BOUND(dev->d_flags);
|
|
}
|
|
|
|
conn->boundto = 0; /* This interface is no longer bound */
|
|
}
|
|
|
|
ret = OK;
|
|
}
|
|
|
|
/* No, we are binding a socket to the interface. */
|
|
|
|
else
|
|
{
|
|
/* Find the interface device with this name */
|
|
|
|
dev = netdev_findbyname(value);
|
|
if (dev == NULL)
|
|
{
|
|
ret = -ENODEV;
|
|
}
|
|
|
|
/* An interface may be bound only to one socket. */
|
|
|
|
else if (IFF_IS_BOUND(dev->d_flags))
|
|
{
|
|
ret = -EBUSY;
|
|
}
|
|
else
|
|
{
|
|
/* Bind the interface to a socket */
|
|
|
|
IFF_SET_BOUND(dev->d_flags);
|
|
|
|
/* Bind the socket to the interface */
|
|
|
|
DEBUGASSERT(dev->d_ifindex > 0 &&
|
|
dev->d_ifindex <= MAX_IFINDEX);
|
|
conn->boundto = dev->d_ifindex;
|
|
ret = OK;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
nerr("ERROR: Unrecognized UDP option: %d\n", option);
|
|
ret = -ENOPROTOOPT;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
#else
|
|
return -ENOPROTOOPT;
|
|
#endif /* CONFIG_NET_UDP_BINDTODEVICE */
|
|
}
|
|
|
|
#endif /* CONFIG_NET_UDPPROTO_OPTIONS */
|