incubator-nuttx/net/udp/udp_setsockopt.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 */