2007-09-07 02:10:10 +02:00
|
|
|
/****************************************************************************
|
2014-06-29 01:25:18 +02:00
|
|
|
* net/socket/setsockopt.c
|
2007-09-07 02:10:10 +02:00
|
|
|
*
|
2021-02-19 12:45:37 +01:00
|
|
|
* 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
|
2007-09-07 02:10:10 +02:00
|
|
|
*
|
2021-02-19 12:45:37 +01:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2007-09-07 02:10:10 +02:00
|
|
|
*
|
2021-02-19 12:45:37 +01:00
|
|
|
* 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.
|
2007-09-07 02:10:10 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
2007-09-08 21:50:59 +02:00
|
|
|
#if defined(CONFIG_NET) && defined(CONFIG_NET_SOCKOPTS)
|
2007-09-07 02:10:10 +02:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
2015-02-15 22:18:35 +01:00
|
|
|
#include <sys/time.h>
|
2007-09-07 02:10:10 +02:00
|
|
|
#include <errno.h>
|
2017-03-31 16:58:14 +02:00
|
|
|
#include <debug.h>
|
|
|
|
#include <assert.h>
|
2007-09-09 00:41:00 +02:00
|
|
|
#include <arch/irq.h>
|
2007-09-07 02:10:10 +02:00
|
|
|
|
2014-07-05 00:38:51 +02:00
|
|
|
#include <nuttx/net/net.h>
|
2022-08-24 04:30:01 +02:00
|
|
|
#include <netdev/netdev.h>
|
2014-07-05 00:38:51 +02:00
|
|
|
|
2014-06-29 01:25:18 +02:00
|
|
|
#include "socket/socket.h"
|
2018-10-31 22:59:05 +01:00
|
|
|
#include "inet/inet.h"
|
2018-03-12 17:59:46 +01:00
|
|
|
#include "tcp/tcp.h"
|
2018-06-25 20:41:28 +02:00
|
|
|
#include "udp/udp.h"
|
2017-03-31 16:58:14 +02:00
|
|
|
#include "usrsock/usrsock.h"
|
2014-06-29 01:25:18 +02:00
|
|
|
#include "utils/utils.h"
|
2020-06-15 19:57:13 +02:00
|
|
|
#include "can/can.h"
|
2007-09-07 02:10:10 +02:00
|
|
|
|
|
|
|
/****************************************************************************
|
2015-01-19 23:02:56 +01:00
|
|
|
* Public Functions
|
2007-09-07 02:10:10 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
2018-03-12 17:59:46 +01:00
|
|
|
* Name: psock_socketlevel_option
|
2007-09-07 02:10:10 +02:00
|
|
|
*
|
|
|
|
* Description:
|
2018-03-12 17:59:46 +01:00
|
|
|
* psock_socketlevel_option() sets the socket-level option specified by the
|
|
|
|
* 'option' argument to the value pointed to by the 'value' argument for
|
|
|
|
* the socket specified by the 'psock' argument.
|
2007-09-07 02:10:10 +02:00
|
|
|
*
|
2018-03-12 17:59:46 +01:00
|
|
|
* See <sys/socket.h> a complete list of values for the socket level
|
|
|
|
* 'option' argument.
|
2007-09-07 02:10:10 +02:00
|
|
|
*
|
2018-03-12 17:59:46 +01:00
|
|
|
* Input Parameters:
|
2012-03-02 20:57:52 +01:00
|
|
|
* psock Socket structure of socket to operate on
|
2007-09-07 02:10:10 +02:00
|
|
|
* option identifies the option to set
|
|
|
|
* value Points to the argument value
|
|
|
|
* value_len The length of the argument value
|
|
|
|
*
|
|
|
|
* Returned Value:
|
2018-03-12 17:59:46 +01:00
|
|
|
* 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.
|
2007-09-07 02:10:10 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2018-03-12 17:59:46 +01:00
|
|
|
static int psock_socketlevel_option(FAR struct socket *psock, int option,
|
2020-05-14 11:45:29 +02:00
|
|
|
FAR const void *value,
|
|
|
|
socklen_t value_len)
|
2007-09-07 02:10:10 +02:00
|
|
|
{
|
2022-02-07 07:20:31 +01:00
|
|
|
FAR struct socket_conn_s *conn = psock->s_conn;
|
|
|
|
|
2007-09-08 21:50:59 +02:00
|
|
|
/* Verify that the socket option if valid (but might not be supported ) */
|
|
|
|
|
2022-09-27 15:52:05 +02:00
|
|
|
if (!value)
|
2007-09-08 21:50:59 +02:00
|
|
|
{
|
2022-10-19 17:15:03 +02:00
|
|
|
return -EFAULT;
|
2007-09-08 21:50:59 +02:00
|
|
|
}
|
|
|
|
|
2021-04-07 10:50:21 +02:00
|
|
|
/* Process the options always handled locally */
|
2020-12-01 13:03:00 +01:00
|
|
|
|
|
|
|
switch (option)
|
2017-03-31 16:58:14 +02:00
|
|
|
{
|
2020-12-01 13:03:00 +01:00
|
|
|
/* The following options take a pointer to an integer boolean value.
|
|
|
|
* We will blindly set the bit here although the implementation
|
|
|
|
* is outside of the scope of setsockopt.
|
|
|
|
*/
|
2017-03-31 16:58:14 +02:00
|
|
|
|
2020-12-01 13:03:00 +01:00
|
|
|
case SO_RCVTIMEO:
|
|
|
|
case SO_SNDTIMEO:
|
|
|
|
{
|
|
|
|
FAR struct timeval *tv = (FAR struct timeval *)value;
|
|
|
|
socktimeo_t timeo;
|
2017-03-31 16:58:14 +02:00
|
|
|
|
2020-12-01 13:03:00 +01:00
|
|
|
/* Verify that option is the size of an 'struct timeval'. */
|
2017-03-31 16:58:14 +02:00
|
|
|
|
2020-12-01 13:03:00 +01:00
|
|
|
if (tv == NULL || value_len != sizeof(struct timeval))
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the timeout value. Any microsecond remainder will be
|
|
|
|
* forced to the next larger, whole decisecond value.
|
|
|
|
*/
|
|
|
|
|
|
|
|
timeo = (socktimeo_t)net_timeval2dsec(tv, TV2DS_CEIL);
|
|
|
|
|
|
|
|
/* Save the timeout value */
|
2017-03-31 16:58:14 +02:00
|
|
|
|
2020-12-01 13:03:00 +01:00
|
|
|
if (option == SO_RCVTIMEO)
|
2017-03-31 16:58:14 +02:00
|
|
|
{
|
2022-02-07 07:36:54 +01:00
|
|
|
conn->s_rcvtimeo = timeo;
|
2020-12-01 13:03:00 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-07 07:36:54 +01:00
|
|
|
conn->s_sndtimeo = timeo;
|
2017-03-31 16:58:14 +02:00
|
|
|
}
|
|
|
|
|
2020-12-01 13:03:00 +01:00
|
|
|
/* Set/clear the corresponding enable/disable bit */
|
2014-01-13 18:58:45 +01:00
|
|
|
|
2020-12-01 13:03:00 +01:00
|
|
|
if (timeo)
|
|
|
|
{
|
2022-02-07 07:20:31 +01:00
|
|
|
_SO_CLROPT(conn->s_options, option);
|
2020-12-01 13:03:00 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-07 07:20:31 +01:00
|
|
|
_SO_SETOPT(conn->s_options, option);
|
2020-12-01 13:03:00 +01:00
|
|
|
}
|
2021-07-05 10:01:48 +02:00
|
|
|
|
|
|
|
return OK;
|
2020-12-01 13:03:00 +01:00
|
|
|
}
|
2021-04-07 10:50:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_USRSOCK
|
|
|
|
if (psock->s_type == SOCK_USRSOCK_TYPE)
|
|
|
|
{
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
#endif
|
2007-09-08 21:50:59 +02:00
|
|
|
|
2021-04-07 10:50:21 +02:00
|
|
|
switch (option)
|
|
|
|
{
|
2007-09-08 21:50:59 +02:00
|
|
|
case SO_BROADCAST: /* Permits sending of broadcast messages */
|
2018-03-13 15:07:03 +01:00
|
|
|
case SO_DEBUG: /* Enables recording of debugging information */
|
|
|
|
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
|
2018-03-12 17:59:46 +01:00
|
|
|
#ifndef CONFIG_NET_TCPPROTO_OPTIONS
|
|
|
|
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
|
|
|
|
* periodic transmission of probes */
|
|
|
|
#endif
|
2007-09-08 21:50:59 +02:00
|
|
|
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
|
2018-03-13 15:07:03 +01:00
|
|
|
case SO_REUSEADDR: /* Allow reuse of local addresses */
|
2007-09-08 21:50:59 +02:00
|
|
|
{
|
|
|
|
int setting;
|
|
|
|
|
|
|
|
/* Verify that option is the size of an 'int'. Should also check
|
|
|
|
* that 'value' is properly aligned for an 'int'
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (value_len != sizeof(int))
|
|
|
|
{
|
2017-09-30 16:18:08 +02:00
|
|
|
return -EINVAL;
|
2013-04-05 14:40:40 +02:00
|
|
|
}
|
2007-09-08 21:50:59 +02:00
|
|
|
|
|
|
|
/* Get the value. Is the option being set or cleared? */
|
|
|
|
|
2015-10-08 23:10:04 +02:00
|
|
|
setting = *(FAR int *)value;
|
2007-09-08 21:50:59 +02:00
|
|
|
|
2018-06-23 23:03:01 +02:00
|
|
|
/* Lock the network so that we have exclusive access to the socket
|
|
|
|
* options.
|
2007-09-08 21:50:59 +02:00
|
|
|
*/
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_lock();
|
2007-09-08 21:50:59 +02:00
|
|
|
|
|
|
|
/* Set or clear the option bit */
|
|
|
|
|
|
|
|
if (setting)
|
|
|
|
{
|
2022-02-07 07:20:31 +01:00
|
|
|
_SO_SETOPT(conn->s_options, option);
|
2007-09-08 21:50:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-07 07:20:31 +01:00
|
|
|
_SO_CLROPT(conn->s_options, option);
|
2007-09-08 21:50:59 +02:00
|
|
|
}
|
2014-01-13 18:58:45 +01:00
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_unlock();
|
2007-09-08 21:50:59 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-03-12 17:59:46 +01:00
|
|
|
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
|
|
|
|
/* Any connection-oriented protocol could potentially support
|
|
|
|
* SO_KEEPALIVE. However, this option is currently only available for
|
|
|
|
* TCP/IP.
|
|
|
|
*
|
|
|
|
* NOTE: SO_KEEPALIVE is not really a socket-level option; it is a
|
|
|
|
* protocol-level option. A given TCP connection may service multiple
|
|
|
|
* sockets (via dup'ing of the socket). There is, however, still only
|
|
|
|
* one connection to be monitored and that is a global attribute across
|
|
|
|
* all of the clones that may use the underlying connection.
|
|
|
|
*/
|
|
|
|
|
|
|
|
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
|
|
|
|
* periodic transmission of probes */
|
|
|
|
return tcp_setsockopt(psock, option, value, value_len);
|
|
|
|
#endif
|
|
|
|
|
2014-01-13 18:58:45 +01:00
|
|
|
#ifdef CONFIG_NET_SOLINGER
|
2018-03-13 15:07:03 +01:00
|
|
|
case SO_LINGER: /* Lingers on a close() if data is present */
|
2014-01-13 18:58:45 +01:00
|
|
|
{
|
|
|
|
FAR struct linger *setting;
|
|
|
|
|
|
|
|
/* Verify that option is at least the size of an 'struct linger'. */
|
|
|
|
|
|
|
|
if (value_len < sizeof(FAR struct linger))
|
|
|
|
{
|
2017-09-30 16:18:08 +02:00
|
|
|
return -EINVAL;
|
2014-01-13 18:58:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the value. Is the option being set or cleared? */
|
|
|
|
|
|
|
|
setting = (FAR struct linger *)value;
|
|
|
|
|
2018-06-23 23:03:01 +02:00
|
|
|
/* Lock the network so that we have exclusive access to the socket
|
|
|
|
* options.
|
2014-01-13 18:58:45 +01:00
|
|
|
*/
|
|
|
|
|
2018-06-23 23:03:01 +02:00
|
|
|
net_lock();
|
2014-01-13 18:58:45 +01:00
|
|
|
|
2020-05-14 11:45:29 +02:00
|
|
|
/* Set or clear the linger option bit and linger time
|
|
|
|
* (in deciseconds)
|
|
|
|
*/
|
2014-01-13 18:58:45 +01:00
|
|
|
|
|
|
|
if (setting->l_onoff)
|
|
|
|
{
|
2022-02-07 07:20:31 +01:00
|
|
|
_SO_SETOPT(conn->s_options, option);
|
2022-02-08 07:53:43 +01:00
|
|
|
conn->s_linger = 10 * setting->l_linger;
|
2014-01-13 18:58:45 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-07 07:20:31 +01:00
|
|
|
_SO_CLROPT(conn->s_options, option);
|
2022-02-08 07:53:43 +01:00
|
|
|
conn->s_linger = 0;
|
2014-01-13 18:58:45 +01:00
|
|
|
}
|
|
|
|
|
2016-12-03 23:28:19 +01:00
|
|
|
net_unlock();
|
2014-01-13 18:58:45 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
2020-06-15 10:23:25 +02:00
|
|
|
|
|
|
|
#ifdef CONFIG_NET_TIMESTAMP
|
|
|
|
case SO_TIMESTAMP: /* Generates a timestamp for each incoming packet */
|
|
|
|
{
|
|
|
|
/* Verify that option is at least the size of an integer. */
|
|
|
|
|
|
|
|
if (value_len < sizeof(FAR int32_t))
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Lock the network so that we have exclusive access to the socket
|
|
|
|
* options.
|
|
|
|
*/
|
|
|
|
|
|
|
|
net_lock();
|
|
|
|
|
2022-02-07 07:46:34 +01:00
|
|
|
conn->s_timestamp = *((FAR int32_t *)value);
|
2020-06-15 10:23:25 +02:00
|
|
|
|
|
|
|
net_unlock();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
2022-03-17 10:54:31 +01:00
|
|
|
|
|
|
|
#if CONFIG_NET_RECV_BUFSIZE > 0
|
|
|
|
case SO_RCVBUF: /* Sets receive buffer size */
|
|
|
|
{
|
|
|
|
int buffersize;
|
|
|
|
|
|
|
|
/* Verify that option is the size of an 'int'. Should also check
|
|
|
|
* that 'value' is properly aligned for an 'int'
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (value_len != sizeof(int))
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the value. Is the option being set or cleared? */
|
|
|
|
|
|
|
|
buffersize = *(FAR int *)value;
|
|
|
|
|
|
|
|
if (buffersize < 0)
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_lock();
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
|
|
|
|
if (psock->s_type == SOCK_STREAM)
|
|
|
|
{
|
|
|
|
FAR struct tcp_conn_s *tcp;
|
|
|
|
|
|
|
|
tcp = (FAR struct tcp_conn_s *)conn;
|
|
|
|
|
|
|
|
/* Save the receive buffer size */
|
|
|
|
|
|
|
|
tcp->rcv_bufs = buffersize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
|
|
|
|
if (psock->s_type == SOCK_DGRAM)
|
|
|
|
{
|
|
|
|
FAR struct udp_conn_s *udp;
|
|
|
|
|
|
|
|
udp = (FAR struct udp_conn_s *)conn;
|
|
|
|
|
|
|
|
/* Save the receive buffer size */
|
|
|
|
|
|
|
|
udp->rcvbufs = buffersize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
net_unlock();
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_unlock();
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if CONFIG_NET_SEND_BUFSIZE > 0
|
|
|
|
case SO_SNDBUF: /* Sets send buffer size */
|
|
|
|
{
|
|
|
|
int buffersize;
|
|
|
|
|
|
|
|
/* Verify that option is the size of an 'int'. Should also check
|
|
|
|
* that 'value' is properly aligned for an 'int'
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (value_len != sizeof(int))
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the value. Is the option being set or cleared? */
|
|
|
|
|
|
|
|
buffersize = *(FAR int *)value;
|
|
|
|
|
|
|
|
if (buffersize < 0)
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_lock();
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK)
|
|
|
|
if (psock->s_type == SOCK_STREAM)
|
|
|
|
{
|
|
|
|
FAR struct tcp_conn_s *tcp;
|
|
|
|
|
|
|
|
tcp = (FAR struct tcp_conn_s *)conn;
|
|
|
|
|
|
|
|
/* Save the send buffer size */
|
|
|
|
|
|
|
|
tcp->snd_bufs = buffersize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
|
|
|
|
if (psock->s_type == SOCK_DGRAM)
|
|
|
|
{
|
|
|
|
FAR struct udp_conn_s *udp;
|
|
|
|
|
|
|
|
udp = (FAR struct udp_conn_s *)conn;
|
|
|
|
|
|
|
|
/* Save the send buffer size */
|
|
|
|
|
|
|
|
udp->sndbufs = buffersize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
net_unlock();
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_unlock();
|
|
|
|
|
2022-08-24 04:30:01 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_BINDTODEVICE
|
|
|
|
/* Handle the SO_BINDTODEVICE socket-level option.
|
|
|
|
*
|
|
|
|
* NOTE: this option 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 SO_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))
|
|
|
|
{
|
|
|
|
conn->s_boundto = 0; /* This interface is no longer bound */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No, we are binding a socket to the interface
|
|
|
|
* Find the interface device with this name.
|
|
|
|
*/
|
|
|
|
|
|
|
|
dev = netdev_findbyname(value);
|
|
|
|
if (dev == NULL)
|
|
|
|
{
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bind the socket to the interface */
|
|
|
|
|
|
|
|
DEBUGASSERT(dev->d_ifindex > 0 &&
|
|
|
|
dev->d_ifindex <= MAX_IFINDEX);
|
|
|
|
conn->s_boundto = dev->d_ifindex;
|
|
|
|
|
2022-03-17 10:54:31 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-09-08 21:50:59 +02:00
|
|
|
/* There options are only valid when used with getopt */
|
|
|
|
|
|
|
|
case SO_ACCEPTCONN: /* Reports whether socket listening is enabled */
|
|
|
|
case SO_ERROR: /* Reports and clears error status. */
|
|
|
|
case SO_TYPE: /* Reports the socket type */
|
2022-09-27 15:52:05 +02:00
|
|
|
return -EINVAL;
|
2007-09-08 21:50:59 +02:00
|
|
|
|
|
|
|
default:
|
2017-09-30 16:18:08 +02:00
|
|
|
return -ENOPROTOOPT;
|
2007-09-08 21:50:59 +02:00
|
|
|
}
|
2013-04-05 14:40:40 +02:00
|
|
|
|
2007-09-08 21:50:59 +02:00
|
|
|
return OK;
|
2007-09-07 02:10:10 +02:00
|
|
|
}
|
|
|
|
|
2018-03-12 17:59:46 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: psock_setsockopt
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* psock_setsockopt() sets the option specified by the 'option' argument,
|
|
|
|
* at the protocol level specified by the 'level' argument, to the value
|
|
|
|
* pointed to by the 'value' argument for the socket specified by the
|
|
|
|
* 'psock' argument.
|
|
|
|
*
|
|
|
|
* The 'level' argument specifies the protocol level of the option. To set
|
|
|
|
* options at the socket level, specify the level argument as SOL_SOCKET.
|
|
|
|
*
|
|
|
|
* See <sys/socket.h> a complete list of values for the socket level
|
|
|
|
* 'option' argument.
|
|
|
|
*
|
2020-05-14 11:45:29 +02:00
|
|
|
* Protocol level options, such as SOL_TCP, are defined in
|
|
|
|
* protocol-specific header files, for example include/netinet/tcp.h
|
2018-03-12 17:59:46 +01:00
|
|
|
*
|
|
|
|
* Input Parameters:
|
|
|
|
* psock Socket structure of socket to operate on
|
|
|
|
* level Protocol level to set the option
|
|
|
|
* 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:
|
|
|
|
*
|
|
|
|
* EDOM
|
|
|
|
* The send and receive timeout values are too big to fit into the
|
|
|
|
* timeout fields in the socket structure.
|
|
|
|
* EINVAL
|
|
|
|
* The specified option is invalid at the specified socket 'level' or the
|
|
|
|
* socket has been shut down.
|
|
|
|
* EISCONN
|
|
|
|
* The socket is already connected, and a specified option cannot be set
|
|
|
|
* while the socket is connected.
|
|
|
|
* ENOPROTOOPT
|
|
|
|
* The 'option' is not supported by the protocol.
|
|
|
|
* ENOTSOCK
|
|
|
|
* The 'sockfd' argument does not refer to a socket.
|
|
|
|
* ENOMEM
|
|
|
|
* There was insufficient memory available for the operation to complete.
|
|
|
|
* ENOBUFS
|
|
|
|
* Insufficient resources are available in the system to complete the
|
|
|
|
* call.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
int psock_setsockopt(FAR struct socket *psock, int level, int option,
|
|
|
|
FAR const void *value, socklen_t value_len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2020-01-31 10:48:46 +01:00
|
|
|
/* Verify that the sockfd corresponds to valid, allocated socket */
|
|
|
|
|
2021-02-23 11:04:13 +01:00
|
|
|
if (psock == NULL || psock->s_conn == NULL)
|
2020-01-31 10:48:46 +01:00
|
|
|
{
|
|
|
|
return -EBADF;
|
|
|
|
}
|
|
|
|
|
2018-03-12 17:59:46 +01:00
|
|
|
/* Handle setting of the socket option according to the level at which
|
|
|
|
* option should be applied.
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (level)
|
|
|
|
{
|
|
|
|
case SOL_SOCKET: /* Socket-level options (see include/sys/socket.h) */
|
2018-10-31 22:59:05 +01:00
|
|
|
ret = psock_socketlevel_option(psock, option, value, value_len);
|
|
|
|
break;
|
2018-03-12 17:59:46 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
|
2020-12-01 08:51:12 +01:00
|
|
|
case IPPROTO_TCP:/* TCP protocol socket options (see include/netinet/tcp.h) */
|
2018-10-31 22:59:05 +01:00
|
|
|
ret = tcp_setsockopt(psock, option, value, value_len);
|
|
|
|
break;
|
2018-03-12 17:59:46 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-25 20:41:28 +02:00
|
|
|
#ifdef CONFIG_NET_UDPPROTO_OPTIONS
|
2020-12-01 08:51:12 +01:00
|
|
|
case IPPROTO_UDP:/* UDP protocol socket options (see include/netinet/udp.h) */
|
2018-10-31 22:59:05 +01:00
|
|
|
ret = udp_setsockopt(psock, option, value, value_len);
|
|
|
|
break;
|
2018-06-25 20:41:28 +02:00
|
|
|
#endif
|
|
|
|
|
2018-10-31 22:59:05 +01:00
|
|
|
#ifdef CONFIG_NET_IPv4
|
2020-06-29 08:05:38 +02:00
|
|
|
case IPPROTO_IP:/* TCP protocol socket options (see include/netinet/in.h) */
|
2018-10-31 22:59:05 +01:00
|
|
|
ret = ipv4_setsockopt(psock, option, value, value_len);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
2020-06-29 08:05:38 +02:00
|
|
|
case IPPROTO_IPV6:/* TCP protocol socket options (see include/netinet/in.h) */
|
2018-10-31 22:59:05 +01:00
|
|
|
ret = ipv6_setsockopt(psock, option, value, value_len);
|
|
|
|
break;
|
|
|
|
#endif
|
2018-03-12 17:59:46 +01:00
|
|
|
|
2020-06-15 10:23:25 +02:00
|
|
|
#ifdef CONFIG_NET_CANPROTO_OPTIONS
|
|
|
|
case SOL_CAN_RAW: /* CAN protocol socket options (see include/netpacket/can.h) */
|
|
|
|
ret = can_setsockopt(psock, option, value, value_len);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2018-03-12 17:59:46 +01:00
|
|
|
default: /* The provided level is invalid */
|
2020-12-01 08:51:12 +01:00
|
|
|
ret = -ENOPROTOOPT;
|
2018-10-31 22:59:05 +01:00
|
|
|
break;
|
2018-03-12 17:59:46 +01:00
|
|
|
}
|
|
|
|
|
2020-12-01 13:03:00 +01:00
|
|
|
#ifdef CONFIG_NET_USRSOCK
|
|
|
|
/* Try usrsock further if the protocol not available */
|
|
|
|
|
|
|
|
if (ret == -ENOPROTOOPT && psock->s_type == SOCK_USRSOCK_TYPE)
|
|
|
|
{
|
|
|
|
ret = usrsock_setsockopt(psock->s_conn, level,
|
|
|
|
option, value, value_len);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-03-12 17:59:46 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-02 20:57:52 +01:00
|
|
|
/****************************************************************************
|
2017-04-22 00:33:14 +02:00
|
|
|
* Name: setsockopt
|
2012-03-02 20:57:52 +01:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* setsockopt() sets the option specified by the 'option' argument,
|
|
|
|
* at the protocol level specified by the 'level' argument, to the value
|
|
|
|
* pointed to by the 'value' argument for the socket associated with the
|
|
|
|
* file descriptor specified by the 'sockfd' argument.
|
|
|
|
*
|
2018-03-12 17:59:46 +01:00
|
|
|
* The 'level' argument specifies the protocol level of the option. To set
|
2012-03-02 20:57:52 +01:00
|
|
|
* options at the socket level, specify the level argument as SOL_SOCKET.
|
|
|
|
*
|
2018-03-12 17:59:46 +01:00
|
|
|
* See <sys/socket.h> a complete list of values for the socket level
|
|
|
|
* 'option' argument.
|
2012-03-02 20:57:52 +01:00
|
|
|
*
|
2020-05-14 11:45:29 +02:00
|
|
|
* Protocol level options, such as SOL_TCP, are defined in
|
|
|
|
* protocol-specific header files, for example include/netinet/tcp.h
|
2018-03-12 17:59:46 +01:00
|
|
|
*
|
|
|
|
* Input Parameters:
|
2012-03-02 20:57:52 +01:00
|
|
|
* sockfd Socket descriptor of socket
|
|
|
|
* level Protocol level to set the option
|
|
|
|
* option identifies the option to set
|
|
|
|
* value Points to the argument value
|
|
|
|
* value_len The length of the argument value
|
|
|
|
*
|
|
|
|
* Returned Value:
|
2018-03-12 17:59:46 +01:00
|
|
|
* 0 on success; -1 on failure
|
2012-03-02 20:57:52 +01:00
|
|
|
*
|
2018-03-12 17:59:46 +01:00
|
|
|
* EBADF
|
|
|
|
* The 'sockfd' argument is not a valid socket descriptor.
|
|
|
|
* EDOM
|
|
|
|
* The send and receive timeout values are too big to fit into the
|
|
|
|
* timeout fields in the socket structure.
|
|
|
|
* EINVAL
|
|
|
|
* The specified option is invalid at the specified socket 'level' or the
|
|
|
|
* socket has been shut down.
|
|
|
|
* EISCONN
|
|
|
|
* The socket is already connected, and a specified option cannot be set
|
|
|
|
* while the socket is connected.
|
|
|
|
* ENOPROTOOPT
|
|
|
|
* The 'option' is not supported by the protocol.
|
|
|
|
* ENOTSOCK
|
|
|
|
* The 'sockfd' argument does not refer to a socket.
|
|
|
|
* ENOMEM
|
|
|
|
* There was insufficient memory available for the operation to complete.
|
|
|
|
* ENOBUFS
|
|
|
|
* Insufficient resources are available in the system to complete the
|
|
|
|
* call.
|
2012-03-02 20:57:52 +01:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-01-11 16:40:32 +01:00
|
|
|
int setsockopt(int sockfd, int level, int option, const void *value,
|
|
|
|
socklen_t value_len)
|
2012-03-02 20:57:52 +01:00
|
|
|
{
|
|
|
|
FAR struct socket *psock;
|
2017-09-30 16:18:08 +02:00
|
|
|
int ret;
|
2012-03-02 20:57:52 +01:00
|
|
|
|
|
|
|
/* Get the underlying socket structure */
|
|
|
|
|
|
|
|
psock = sockfd_socket(sockfd);
|
|
|
|
|
|
|
|
/* Then let psock_setockopt() do all of the work */
|
|
|
|
|
2017-09-30 16:18:08 +02:00
|
|
|
ret = psock_setsockopt(psock, level, option, value, value_len);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
2020-05-13 06:08:32 +02:00
|
|
|
set_errno(-ret);
|
2017-09-30 16:18:08 +02:00
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
2012-03-02 20:57:52 +01:00
|
|
|
}
|
|
|
|
|
2007-09-08 21:50:59 +02:00
|
|
|
#endif /* CONFIG_NET && CONFIG_NET_SOCKOPTS */
|