1654 lines
46 KiB
C
1654 lines
46 KiB
C
/*
|
|
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
|
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <lwip/sockets.h>
|
|
#include <lwip/priv/tcpip_priv.h>
|
|
#include <lwip/fixme.h>
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
#include "capability_type.h"
|
|
#include "capability_api.h"
|
|
#define BIND_SERVICE_CAP_MIN_PORT 1024
|
|
#endif
|
|
|
|
#define IOCTL_CMD_CASE_HANDLER() \
|
|
{ \
|
|
err_t err; \
|
|
struct lwip_ioctl_apimsg msg; \
|
|
msg.sock = sock; \
|
|
msg.cmd = cmd; \
|
|
msg.argp = argp; \
|
|
\
|
|
err = tcpip_api_call(lwip_do_ioctl_impl, &msg.call); \
|
|
if (err != ENOSYS) { \
|
|
sock_set_errno(sock, err); \
|
|
done_socket(sock); \
|
|
return -(err != ERR_OK); \
|
|
} \
|
|
}
|
|
|
|
struct lwip_ioctl_apimsg {
|
|
struct tcpip_api_call_data call;
|
|
struct lwip_sock *sock;
|
|
long cmd;
|
|
void *argp;
|
|
};
|
|
|
|
static err_t lwip_do_ioctl_impl(struct tcpip_api_call_data *call);
|
|
|
|
static void poll_check_waiters(int s, int check_waiters);
|
|
|
|
static int lwip_socket_wrap(int domain, int type, int protocol);
|
|
int lwip_socket(int domain, int type, int protocol)
|
|
{
|
|
return lwip_socket_wrap(domain, type, protocol);
|
|
}
|
|
|
|
static int lwip_setsockopt_wrap(int s, int level, int optname, const void *optval, socklen_t optlen);
|
|
int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
|
|
{
|
|
return lwip_setsockopt_wrap(s, level, optname, optval, optlen);
|
|
}
|
|
|
|
static int lwip_bind_wrap(int s, const struct sockaddr *name, socklen_t namelen);
|
|
int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
|
|
{
|
|
return lwip_bind_wrap(s, name, namelen);
|
|
}
|
|
|
|
static ssize_t lwip_sendto_wrap(int s, const void *dataptr, size_t size, int flags,
|
|
const struct sockaddr *to, socklen_t tolen);
|
|
ssize_t lwip_sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
|
|
{
|
|
return lwip_sendto_wrap(s, dataptr, size, flags, to, tolen);
|
|
}
|
|
|
|
#ifdef lwip_socket
|
|
#undef lwip_socket
|
|
#endif
|
|
#define lwip_socket static lwip_socket2
|
|
static int lwip_socket2(int domain, int type, int protocol);
|
|
|
|
#ifdef lwip_setsockopt
|
|
#undef lwip_setsockopt
|
|
#endif
|
|
#define lwip_setsockopt static lwip_setsockopt2
|
|
static int lwip_setsockopt2(int s, int level, int optname, const void *optval, socklen_t optlen);
|
|
|
|
#ifdef lwip_bind
|
|
#undef lwip_bind
|
|
#endif
|
|
#define lwip_bind static lwip_bind2
|
|
static int lwip_bind2(int s, const struct sockaddr *name, socklen_t namelen);
|
|
|
|
#ifdef lwip_sendto
|
|
#undef lwip_sendto
|
|
#endif
|
|
#define lwip_sendto lwip_sendto2
|
|
ssize_t lwip_sendto2(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen);
|
|
|
|
#include "../api/sockets.c"
|
|
|
|
#undef lwip_socket
|
|
#undef lwip_setsockopt
|
|
#undef lwip_bind
|
|
#undef lwip_sendto
|
|
|
|
static int lwip_socket_wrap(int domain, int type, int protocol)
|
|
{
|
|
if (domain != AF_INET && domain != AF_INET6) {
|
|
set_errno(EAFNOSUPPORT);
|
|
return -1;
|
|
}
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (type == SOCK_RAW && !IsCapPermit(CAP_NET_RAW)) {
|
|
set_errno(EPERM);
|
|
return -1;
|
|
}
|
|
#endif
|
|
return lwip_socket2(domain, type, protocol);
|
|
}
|
|
|
|
static int lwip_setsockopt_wrap(int s, int level, int optname, const void *optval, socklen_t optlen)
|
|
{
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (level == SOL_SOCKET) {
|
|
switch (optname) {
|
|
#if LWIP_ENABLE_CAP_NET_BROADCAST
|
|
case SO_BROADCAST:
|
|
if (!IsCapPermit(CAP_NET_BROADCAST)) {
|
|
set_errno(EPERM);
|
|
return -1;
|
|
}
|
|
break;
|
|
#endif
|
|
case SO_DEBUG:
|
|
case SO_MARK:
|
|
case SO_PRIORITY:
|
|
case SO_RCVBUFFORCE:
|
|
case SO_SNDBUFFORCE:
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
set_errno(EPERM);
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
return lwip_setsockopt2(s, level, optname, optval, optlen);
|
|
}
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY && LWIP_ENABLE_CAP_NET_BROADCAST
|
|
static int ip_addr_isbroadcast_bysock(const ip_addr_t *ipaddr, int s)
|
|
{
|
|
struct sockaddr sa;
|
|
socklen_t salen = sizeof(sa);
|
|
|
|
if (ipaddr == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (lwip_getsockname(s, &sa, &salen) == -1) {
|
|
return 0;
|
|
}
|
|
|
|
ip_addr_t addr;
|
|
u16_t port;
|
|
|
|
SOCKADDR_TO_IPADDR_PORT(&sa, &addr, port);
|
|
|
|
struct netif *netif = NULL;
|
|
NETIF_FOREACH(netif) {
|
|
if (ip_addr_cmp(&netif->ip_addr, &addr)) {
|
|
return ip_addr_isbroadcast(ipaddr, netif);
|
|
}
|
|
for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
|
if (ip_addr_cmp(&netif->ip6_addr[i], &addr)) {
|
|
return ip_addr_isbroadcast(ipaddr, netif);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int lwip_bind_wrap(int s, const struct sockaddr *name, socklen_t namelen)
|
|
{
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if ((name->sa_family == AF_INET && namelen >= sizeof(struct sockaddr_in)) ||
|
|
(name->sa_family == AF_INET6 && namelen >= sizeof(struct sockaddr_in6))) {
|
|
ip_addr_t ipaddr;
|
|
u16_t port;
|
|
|
|
SOCKADDR_TO_IPADDR_PORT(name, &ipaddr, port);
|
|
|
|
if (port != 0 && port < BIND_SERVICE_CAP_MIN_PORT) {
|
|
LWIP_ERROR("permission deny: NET_BIND_SERVICE\n", IsCapPermit(CAP_NET_BIND_SERVICE),
|
|
set_errno(EPERM); return -1);
|
|
}
|
|
#if LWIP_ENABLE_CAP_NET_BROADCAST
|
|
if (ip_addr_ismulticast(&ipaddr) || ip_addr_isbroadcast_bysock(&ipaddr, s)) {
|
|
LWIP_ERROR("permission deny: NET_BROADCAST\n", IsCapPermit(CAP_NET_BROADCAST),
|
|
set_errno(EPERM); return -1);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
return lwip_bind2(s, name, namelen);
|
|
}
|
|
|
|
static ssize_t lwip_sendto_wrap(int s, const void *dataptr, size_t size, int flags,
|
|
const struct sockaddr *to, socklen_t tolen)
|
|
{
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (to &&
|
|
((to->sa_family == AF_INET && tolen >= sizeof(struct sockaddr_in)) ||
|
|
(to->sa_family == AF_INET6 && tolen >= sizeof(struct sockaddr_in6)))) {
|
|
ip_addr_t ipaddr;
|
|
u16_t port;
|
|
|
|
SOCKADDR_TO_IPADDR_PORT(to, &ipaddr, port);
|
|
#if LWIP_ENABLE_CAP_NET_BROADCAST
|
|
if (ip_addr_ismulticast(&ipaddr) || ip_addr_isbroadcast_bysock(&ipaddr, s)) {
|
|
LWIP_ERROR("permission deny: NET_BROADCAST\n", IsCapPermit(CAP_NET_BROADCAST),
|
|
set_errno(EPERM); return -1);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
return lwip_sendto2(s, dataptr, size, flags, to, tolen);
|
|
}
|
|
|
|
#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
|
|
|
|
struct file;
|
|
extern void poll_wait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p);
|
|
extern void __wake_up_interruptible_poll(wait_queue_head_t *wait, pollevent_t key);
|
|
|
|
static void poll_check_waiters(int s, int check_waiters)
|
|
{
|
|
unsigned long int_save, wq_empty;
|
|
pollevent_t mask = 0;
|
|
struct lwip_sock *sock;
|
|
SYS_ARCH_DECL_PROTECT(lev);
|
|
|
|
if (!check_waiters) {
|
|
return;
|
|
}
|
|
|
|
sock = get_socket(s);
|
|
if (!sock) {
|
|
return;
|
|
}
|
|
|
|
SYS_ARCH_PROTECT(lev);
|
|
|
|
mask |= (sock->rcvevent > 0) ? (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND) : 0;
|
|
mask |= (sock->sendevent != 0) ? (POLLOUT | POLLWRNORM | POLLWRBAND) : 0;
|
|
mask |= (sock->errevent != 0) ? (POLLERR) : 0;
|
|
|
|
SYS_ARCH_UNPROTECT(lev);
|
|
|
|
spin_lock_irqsave(&sock->wq.lock, int_save);
|
|
wq_empty = LOS_ListEmpty(&(sock->wq.poll_queue));
|
|
spin_unlock_irqrestore(&sock->wq.lock, int_save);
|
|
|
|
if (mask && !wq_empty) {
|
|
__wake_up_interruptible_poll(&sock->wq, mask);
|
|
}
|
|
|
|
done_socket(sock);
|
|
}
|
|
|
|
int socks_poll(int s, poll_table *wait)
|
|
{
|
|
int ret;
|
|
pollevent_t mask = 0;
|
|
struct lwip_sock *sock;
|
|
SYS_ARCH_DECL_PROTECT(lev);
|
|
|
|
LWIP_ERROR("sock_poll: invalid poll_table", (wait != NULL), return -EINVAL;);
|
|
|
|
sock = get_socket(s);
|
|
if (!sock) {
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("sock_poll: Invalid socket"));
|
|
set_errno(EBADF);
|
|
return -EBADF; /* compatible with file poll */
|
|
}
|
|
|
|
SYS_ARCH_PROTECT(lev);
|
|
|
|
mask |= (sock->rcvevent > 0 || sock->lastdata.pbuf) ? (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND) : 0;
|
|
mask |= (sock->sendevent != 0) ? (POLLOUT | POLLWRNORM | POLLWRBAND) : 0;
|
|
mask |= (sock->errevent != 0) ? (POLLERR) : 0;
|
|
|
|
SYS_ARCH_UNPROTECT(lev);
|
|
|
|
ret = wait->key & mask;
|
|
if (!ret) {
|
|
poll_wait(NULL, &sock->wq, wait);
|
|
}
|
|
|
|
done_socket(sock);
|
|
return ret;
|
|
}
|
|
|
|
#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
|
|
|
|
#if !LWIP_COMPAT_SOCKETS
|
|
|
|
#define API_ALIAS(old, new) \
|
|
extern __typeof(old) new __attribute__((__weak__, __alias__(#old)))
|
|
|
|
API_ALIAS(lwip_ioctl, ioctlsocket);
|
|
|
|
#endif /* !LWIP_COMPAT_SOCKETS */
|
|
|
|
#if LWIP_ENABLE_LOS_SHELL_CMD
|
|
/* get numbers of unused sockets */
|
|
int get_unused_socket_num(void)
|
|
{
|
|
int unused = 0;
|
|
SYS_ARCH_DECL_PROTECT(lev);
|
|
|
|
SYS_ARCH_PROTECT(lev);
|
|
|
|
for (int i = 0; i < NUM_SOCKETS; i++) {
|
|
if (sockets[i].conn == NULL) {
|
|
#if LWIP_NETCONN_FULLDUPLEX
|
|
if (sockets[i].fd_used) {
|
|
continue;
|
|
}
|
|
#endif
|
|
unused++;
|
|
}
|
|
}
|
|
|
|
SYS_ARCH_UNPROTECT(lev);
|
|
|
|
return unused;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* socket ioctl
|
|
*/
|
|
|
|
// Options for lwip ioctl
|
|
#define LWIP_IOCTL_ROUTE 1
|
|
#define LWIP_IOCTL_IF 1
|
|
#define LWIP_NETIF_ETHTOOL 0
|
|
#define LWIP_IOCTL_IPV6DPCTD 0
|
|
#undef LWIP_IPV6_DUP_DETECT_ATTEMPTS
|
|
#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 0
|
|
|
|
#ifndef SIOCSIPV6DAD
|
|
#define SIOCSIPV6DAD _IOW('z', 0, unsigned long) /* set DAD enable/disable on netif */
|
|
#endif
|
|
|
|
#ifndef SIOCGIPV6DAD
|
|
#define SIOCGIPV6DAD _IOR('z', 1, unsigned long) /* get DAD status on netif */
|
|
#endif
|
|
|
|
#ifndef SIOCSIPV6DPCTD
|
|
#define SIOCSIPV6DPCTD _IOW('z', 2, unsigned long)
|
|
#endif
|
|
|
|
#ifndef SIOCGIPV6DPCTD
|
|
#define SIOCGIPV6DPCTD _IOR('z', 3, unsigned long)
|
|
#endif
|
|
|
|
#ifndef SIOCETHTOOL
|
|
#define SIOCETHTOOL 0x8946
|
|
#endif
|
|
|
|
#if LWIP_NETIF_PROMISC
|
|
#define NETIF_FLAG_PROMISC 0x80U
|
|
#endif /* LWIP_NETIF_PROMISC */
|
|
|
|
|
|
#if LWIP_IOCTL_ROUTE
|
|
|
|
#include <net/route.h>
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCADDRT(struct rtentry *rmten)
|
|
{
|
|
struct netif *netif = NULL;
|
|
ip_addr_t rtgw_addr;
|
|
u16_t rtgw_port;
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
SOCKADDR_TO_IPADDR_PORT(&rmten->rt_gateway, &rtgw_addr, rtgw_port);
|
|
|
|
if (!IP_IS_V4_VAL(rtgw_addr)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
/* check if multicast/0/loopback */
|
|
if (ip_addr_ismulticast(&rtgw_addr) || ip_addr_isany(&rtgw_addr) ||
|
|
ip_addr_isloopback(&rtgw_addr)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
/* check if reachable */
|
|
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
|
if (ip_addr_netcmp(&rtgw_addr, &netif->ip_addr, ip_2_ip4(&netif->netmask))) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (netif == NULL) {
|
|
return EHOSTUNREACH;
|
|
}
|
|
|
|
/* check if broadcast */
|
|
if (ip_addr_isbroadcast(&rtgw_addr, netif) != 0) {
|
|
return EINVAL;
|
|
}
|
|
|
|
/* Check flags */
|
|
if ((rmten->rt_flags & RTF_GATEWAY) == 0) {
|
|
return EINVAL;
|
|
}
|
|
|
|
/* Add validation */
|
|
if ((netif_default != NULL) && (netif_default != netif)) {
|
|
ip_addr_set_zero(&netif_default->gw);
|
|
(void)netif_set_default(netif);
|
|
}
|
|
netif_set_gw(netif, ip_2_ip4(&rtgw_addr));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if LWIP_IOCTL_IF
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIFCONF(struct ifreq *ifr)
|
|
{
|
|
struct ifconf *ifc = NULL;
|
|
struct netif *netif = NULL;
|
|
struct ifreq ifreq;
|
|
struct sockaddr_in *sock_in = NULL;
|
|
int pos;
|
|
int len;
|
|
int ret;
|
|
|
|
/* Format the caller's buffer. */
|
|
ifc = (struct ifconf *)ifr;
|
|
len = ifc->ifc_len;
|
|
|
|
/* Loop over the interfaces, and write an info block for each. */
|
|
pos = 0;
|
|
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
|
if (ifc->ifc_buf == NULL) {
|
|
pos = (pos + (int)sizeof(struct ifreq));
|
|
continue;
|
|
}
|
|
|
|
if (len < (int)sizeof(ifreq)) {
|
|
break;
|
|
}
|
|
(void)memset_s(&ifreq, sizeof(struct ifreq), 0, sizeof(struct ifreq));
|
|
if (netif->link_layer_type == LOOPBACK_IF) {
|
|
ret = snprintf_s(ifreq.ifr_name, IFNAMSIZ, (IFNAMSIZ - 1), "%.2s", netif->name);
|
|
if ((ret <= 0) || (ret >= IFNAMSIZ)) {
|
|
LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed."));
|
|
return ENOBUFS;
|
|
}
|
|
} else {
|
|
ret = snprintf_s(ifreq.ifr_name, IFNAMSIZ, (IFNAMSIZ - 1), "%s", netif_get_name(netif));
|
|
if ((ret <= 0) || (ret >= IFNAMSIZ)) {
|
|
LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed."));
|
|
return ENOBUFS;
|
|
}
|
|
}
|
|
|
|
sock_in = (struct sockaddr_in *)&ifreq.ifr_addr;
|
|
sock_in->sin_family = AF_INET;
|
|
sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr;
|
|
if (memcpy_s(ifc->ifc_buf + pos, sizeof(struct ifreq), &ifreq, sizeof(struct ifreq)) != EOK) {
|
|
return ENOBUFS;
|
|
}
|
|
pos = pos + (int)sizeof(struct ifreq);
|
|
len = len - (int)sizeof(struct ifreq);
|
|
}
|
|
|
|
ifc->ifc_len = pos;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIFADDR(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
struct sockaddr_in *sock_in = NULL;
|
|
|
|
/* get netif ipaddr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
} else {
|
|
sock_in = (struct sockaddr_in *)&ifr->ifr_addr;
|
|
sock_in->sin_family = AF_INET;
|
|
sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#ifndef LWIP_IPV6_PREFIX_LEN
|
|
#define LWIP_IPV6_PREFIX_LEN 64
|
|
#endif
|
|
|
|
#ifndef LWIP_NETIF_IFINDEX_MAX_EX
|
|
#define LWIP_NETIF_IFINDEX_MAX_EX 255
|
|
#endif
|
|
|
|
#include "lwip/dhcp.h"
|
|
#include "lwip/dhcp6.h"
|
|
#include "lwip/prot/dhcp.h"
|
|
#include "lwip/prot/dhcp6.h"
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCSIFADDR_6(struct ifreq *ifr)
|
|
{
|
|
(void)ifr;
|
|
return ENOSYS;
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCSIFADDR(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
|
|
struct netif *loc_netif = NULL;
|
|
ip_addr_t taget_addr;
|
|
u16_t taget_port;
|
|
SOCKADDR_TO_IPADDR_PORT(&ifr->ifr_addr, &taget_addr, taget_port);
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
/* set netif ipaddr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
}
|
|
#if LWIP_HAVE_LOOPIF
|
|
else if (netif->link_layer_type == LOOPBACK_IF) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
else {
|
|
/* check the address is not multicast/broadcast/0/loopback */
|
|
if (!IP_IS_V4(&taget_addr) || ip_addr_ismulticast(&taget_addr) ||
|
|
ip_addr_isbroadcast(&taget_addr, netif) ||
|
|
ip_addr_isany(&taget_addr) ||
|
|
ip_addr_isloopback(&taget_addr)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
/* reset gateway if new and previous ipaddr not in same net */
|
|
if (ip_addr_netcmp(&taget_addr, &netif->ip_addr, ip_2_ip4(&netif->netmask)) == 0) {
|
|
ip_addr_set_zero(&netif->gw);
|
|
if (netif == netif_default) {
|
|
(void)netif_set_default(NULL);
|
|
}
|
|
}
|
|
|
|
/* lwip disallow two netif sit in same net at the same time */
|
|
loc_netif = netif_list;
|
|
while (loc_netif != NULL) {
|
|
if (loc_netif == netif) {
|
|
loc_netif = loc_netif->next;
|
|
continue;
|
|
}
|
|
if (ip_addr_cmp(&netif->netmask, &loc_netif->netmask) &&
|
|
ip_addr_netcmp(&loc_netif->ip_addr, &taget_addr,
|
|
ip_2_ip4(&netif->netmask))) {
|
|
return EINVAL;
|
|
}
|
|
loc_netif = loc_netif->next;
|
|
}
|
|
|
|
#if LWIP_DHCP
|
|
if ((netif_dhcp_data(netif) != NULL) &&
|
|
(netif_dhcp_data(netif)->state != DHCP_STATE_OFF)) {
|
|
(void)netif_dhcp_off(netif);
|
|
}
|
|
#endif
|
|
|
|
#if LWIP_ARP
|
|
/* clear ARP cache when IP address changed */
|
|
if ((netif->flags & NETIF_FLAG_ETHARP) != 0) {
|
|
etharp_cleanup_netif(netif);
|
|
}
|
|
#endif /* LWIP_ARP */
|
|
|
|
netif_set_ipaddr(netif, ip_2_ip4(&taget_addr));
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCDIFADDR_6(struct ifreq *ifr)
|
|
{
|
|
(void)ifr;
|
|
return ENOSYS;
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCDIFADDR(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
|
|
ip_addr_t target_addr;
|
|
u16_t target_port;
|
|
|
|
SOCKADDR_TO_IPADDR_PORT(&ifr->ifr_addr, &target_addr, target_port);
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
/* set netif ipaddr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
}
|
|
#if LWIP_HAVE_LOOPIF
|
|
else if (netif->link_layer_type == LOOPBACK_IF) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
/* check the address is not loopback */
|
|
if (!IP_IS_V4(&target_addr) || ip_addr_isloopback(&target_addr)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
#if LWIP_DHCP
|
|
if ((netif_dhcp_data(netif) != NULL) &&
|
|
(netif_dhcp_data(netif)->state != DHCP_STATE_OFF)) {
|
|
(void)netif_dhcp_off(netif);
|
|
}
|
|
#endif
|
|
|
|
ip_addr_set_zero(&netif->gw);
|
|
ip_addr_set_zero(&netif->ip_addr);
|
|
ip_addr_set_zero(&netif->netmask);
|
|
if (netif == netif_default) {
|
|
(void)netif_set_default(NULL);
|
|
}
|
|
|
|
#if LWIP_IPV4 && LWIP_ARP
|
|
if ((netif->flags & NETIF_FLAG_ETHARP) != 0) {
|
|
etharp_cleanup_netif(netif);
|
|
}
|
|
#endif /* LWIP_IPV4 && LWIP_ARP */
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIFNETMASK(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
struct sockaddr_in *sock_in = NULL;
|
|
|
|
/* get netif netmask */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
} else {
|
|
sock_in = (struct sockaddr_in *)&ifr->ifr_netmask;
|
|
sock_in->sin_family = AF_INET;
|
|
sock_in->sin_addr.s_addr = ip_2_ip4(&netif->netmask)->addr;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCSIFNETMASK(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
|
|
struct netif *loc_netif = NULL;
|
|
ip_addr_t taget_addr;
|
|
u16_t taget_port;
|
|
SOCKADDR_TO_IPADDR_PORT(&ifr->ifr_addr, &taget_addr, taget_port);
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
if (!IP_IS_V4(&taget_addr)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
/* set netif netmask */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
}
|
|
#if LWIP_HAVE_LOOPIF
|
|
else if (netif->link_layer_type == LOOPBACK_IF) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
else {
|
|
if (ip_addr_cmp(&netif->netmask, &taget_addr)) {
|
|
return 0;
|
|
}
|
|
/* check data valid */
|
|
if (ip_addr_netmask_valid(ip_2_ip4(&taget_addr)) != 0) {
|
|
return EINVAL;
|
|
}
|
|
|
|
/* lwip disallow two netif sit in same net at the same time */
|
|
loc_netif = netif_list;
|
|
while (loc_netif != NULL) {
|
|
if (loc_netif == netif) {
|
|
loc_netif = loc_netif->next;
|
|
continue;
|
|
}
|
|
if (ip_addr_cmp(&loc_netif->netmask, &taget_addr) &&
|
|
ip_addr_netcmp(&loc_netif->ip_addr,
|
|
&netif->ip_addr, ip_2_ip4(&loc_netif->netmask))) {
|
|
return EINVAL;
|
|
}
|
|
loc_netif = loc_netif->next;
|
|
}
|
|
|
|
#if LWIP_DHCP
|
|
if ((netif_dhcp_data(netif) != NULL) &&
|
|
(netif_dhcp_data(netif)->state != DHCP_STATE_OFF)) {
|
|
(void)netif_dhcp_off(netif);
|
|
}
|
|
#endif
|
|
|
|
netif_set_netmask(netif, ip_2_ip4(&taget_addr));
|
|
|
|
/* check if gateway still reachable */
|
|
if (!ip_addr_netcmp(&netif->gw, &netif->ip_addr, ip_2_ip4(&taget_addr))) {
|
|
ip_addr_set_zero(&(netif->gw));
|
|
if (netif == netif_default) {
|
|
(void)netif_set_default(NULL);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCSIFHWADDR(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
err_t ret;
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
/* set netif hw addr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
}
|
|
#if LWIP_HAVE_LOOPIF
|
|
else if (netif->link_layer_type == LOOPBACK_IF) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
else {
|
|
|
|
/* bring netif down to clear all Neighbor Cache Entry */
|
|
(void)netif_set_down(netif);
|
|
|
|
ret = netif_set_hwaddr(netif, (const unsigned char *)ifr->ifr_hwaddr.sa_data, netif->hwaddr_len);
|
|
|
|
if (ret != ERR_OK) {
|
|
(void)netif_set_up(netif);
|
|
return err_to_errno(ret);
|
|
}
|
|
|
|
/*
|
|
* bring netif up to try to send GARP/IGMP/NA/MLD/RS. GARP and NA would
|
|
* make the neighboring nodes update their Neighbor Cache immediately.
|
|
*/
|
|
(void)netif_set_up(netif);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIFHWADDR(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
|
|
/* get netif hw addr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
}
|
|
#if LWIP_HAVE_LOOPIF
|
|
else if (netif->link_layer_type == LOOPBACK_IF) {
|
|
return EPERM;
|
|
}
|
|
#endif /* LWIP_HAVE_LOOPIF */
|
|
else {
|
|
if (memcpy_s((void *)ifr->ifr_hwaddr.sa_data, sizeof(ifr->ifr_hwaddr.sa_data),
|
|
(void *)netif->hwaddr, netif->hwaddr_len) != EOK) {
|
|
return EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCSIFFLAGS(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
/* set netif hw addr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
}
|
|
#if LWIP_HAVE_LOOPIF
|
|
else if (netif->link_layer_type == LOOPBACK_IF) {
|
|
return EPERM;
|
|
}
|
|
#endif /* LWIP_HAVE_LOOPIF */
|
|
else {
|
|
if (((unsigned short)ifr->ifr_flags & IFF_UP) && !(netif->flags & NETIF_FLAG_UP)) {
|
|
(void)netif_set_up(netif);
|
|
} else if (!((unsigned short)ifr->ifr_flags & IFF_UP) && (netif->flags & NETIF_FLAG_UP)) {
|
|
(void)netif_set_down(netif);
|
|
}
|
|
if (((unsigned short)ifr->ifr_flags & IFF_RUNNING) && !(netif->flags & NETIF_FLAG_LINK_UP)) {
|
|
(void)netif_set_link_up(netif);
|
|
} else if (!((unsigned short)ifr->ifr_flags & IFF_RUNNING) && (netif->flags & NETIF_FLAG_LINK_UP)) {
|
|
(void)netif_set_link_down(netif);
|
|
}
|
|
|
|
if ((unsigned short)ifr->ifr_flags & IFF_BROADCAST) {
|
|
netif->flags |= NETIF_FLAG_BROADCAST;
|
|
} else {
|
|
netif->flags = netif->flags & (~NETIF_FLAG_BROADCAST);
|
|
}
|
|
if ((unsigned short)ifr->ifr_flags & IFF_NOARP) {
|
|
netif->flags = (netif->flags & (~NETIF_FLAG_ETHARP));
|
|
} else {
|
|
netif->flags |= NETIF_FLAG_ETHARP;
|
|
}
|
|
|
|
if ((unsigned short)ifr->ifr_flags & IFF_MULTICAST) {
|
|
#if LWIP_IGMP
|
|
netif->flags |= NETIF_FLAG_IGMP;
|
|
#endif /* LWIP_IGMP */
|
|
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
|
netif->flags |= NETIF_FLAG_MLD6;
|
|
#endif /* LWIP_IPV6_MLD */
|
|
} else {
|
|
#if LWIP_IGMP
|
|
netif->flags = (netif->flags & ~NETIF_FLAG_IGMP);
|
|
#endif /* LWIP_IGMP */
|
|
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
|
netif->flags = (netif->flags & ~NETIF_FLAG_MLD6);
|
|
#endif /* LWIP_IPV6_MLD */
|
|
}
|
|
|
|
#if LWIP_DHCP
|
|
if ((unsigned short)ifr->ifr_flags & IFF_DYNAMIC) {
|
|
(void)dhcp_start(netif);
|
|
} else {
|
|
dhcp_stop(netif);
|
|
#if !LWIP_DHCP_SUBSTITUTE
|
|
dhcp_cleanup(netif);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if LWIP_NETIF_PROMISC
|
|
if (((unsigned short)ifr->ifr_flags & IFF_PROMISC)) {
|
|
netif->flags |= NETIF_FLAG_PROMISC;
|
|
} else {
|
|
netif->flags &= ~NETIF_FLAG_PROMISC;
|
|
}
|
|
if (netif->drv_config) {
|
|
netif->drv_config(netif, IFF_PROMISC, !!((unsigned short)ifr->ifr_flags & IFF_PROMISC));
|
|
}
|
|
#endif /* LWIP_NETIF_PROMISC */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIFFLAGS(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
|
|
/* set netif hw addr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
} else {
|
|
if (netif->flags & NETIF_FLAG_UP) {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_UP;
|
|
} else {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_UP;
|
|
}
|
|
if (netif->flags & NETIF_FLAG_LINK_UP) {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_RUNNING;
|
|
} else {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_RUNNING;
|
|
}
|
|
if (netif->flags & NETIF_FLAG_BROADCAST) {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_BROADCAST;
|
|
} else {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_BROADCAST;
|
|
}
|
|
if (netif->flags & NETIF_FLAG_ETHARP) {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_NOARP;
|
|
} else {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_NOARP;
|
|
}
|
|
|
|
#if LWIP_IGMP || LWIP_IPV6_MLD
|
|
if (
|
|
#if LWIP_IGMP
|
|
(netif->flags & NETIF_FLAG_IGMP)
|
|
#endif /* LWIP_IGMP */
|
|
#if LWIP_IGMP && LWIP_IPV6_MLD
|
|
||
|
|
#endif /* LWIP_IGMP && LWIP_IPV6_MLD */
|
|
#if LWIP_IPV6_MLD
|
|
(netif->flags & NETIF_FLAG_MLD6)
|
|
#endif /* LWIP_IPV6_MLD */
|
|
) {
|
|
ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_MULTICAST);
|
|
} else {
|
|
ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_MULTICAST));
|
|
}
|
|
#endif /* LWIP_IGMP || LWIP_IPV6_MLD */
|
|
|
|
#if LWIP_DHCP
|
|
//if ((netif->flags & NETIF_FLAG_DHCP) != 0) {
|
|
if (dhcp_supplied_address(netif)) {
|
|
ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_DYNAMIC);
|
|
} else {
|
|
ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_DYNAMIC));
|
|
}
|
|
#endif
|
|
|
|
#if LWIP_HAVE_LOOPIF
|
|
if (netif->link_layer_type == LOOPBACK_IF) {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_LOOPBACK;
|
|
}
|
|
#endif
|
|
|
|
#if LWIP_NETIF_PROMISC
|
|
if (netif->flags & NETIF_FLAG_PROMISC) {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) | IFF_PROMISC;
|
|
} else {
|
|
ifr->ifr_flags = ((unsigned short)(ifr->ifr_flags)) & ~IFF_PROMISC;
|
|
}
|
|
#endif /* LWIP_NETIF_PROMISC */
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIFNAME(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
int ret;
|
|
|
|
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
|
if (ifr->ifr_ifindex == netif_get_index(netif)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
} else {
|
|
if (netif->link_layer_type == LOOPBACK_IF) {
|
|
ret = snprintf_s(ifr->ifr_name, IFNAMSIZ, (IFNAMSIZ - 1), "%.2s", netif->name);
|
|
if ((ret <= 0) || (ret >= IFNAMSIZ)) {
|
|
return ENOBUFS;
|
|
}
|
|
} else {
|
|
ret = snprintf_s(ifr->ifr_name, IFNAMSIZ, (IFNAMSIZ - 1), "%s", netif_get_name(netif));
|
|
if ((ret <= 0) || (ret >= IFNAMSIZ)) {
|
|
return ENOBUFS;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static bool lwip_validate_ifname(const char *name, u8_t *let_pos)
|
|
{
|
|
unsigned short num_pos = 0;
|
|
unsigned short letter_pos = 0;
|
|
unsigned short pos = 0;
|
|
bool have_num = 0;
|
|
|
|
/* if the first position of variable name is not letter, such as '6eth2' */
|
|
if (((*name >= 'a') && (*name <= 'z')) || ((*name >= 'A') && (*name <= 'Z'))) {
|
|
return 0;
|
|
}
|
|
|
|
/* check if the position of letter is bigger than the the position of digital */
|
|
while (*name != '\0') {
|
|
if ((*name >= '0') && (*name <= '9')) {
|
|
num_pos = pos;
|
|
have_num = 1;
|
|
} else if (((*name >= 'a') && (*name <= 'z')) || ((*name >= 'A') && (*name <= 'Z'))) {
|
|
letter_pos = pos;
|
|
if (have_num != 0) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
pos++;
|
|
name++;
|
|
}
|
|
|
|
/* for the speacil case as all position of variable name is letter, such as 'ethabc' */
|
|
if (num_pos == 0) {
|
|
return 0;
|
|
}
|
|
|
|
/* cheak if the digital in the variable name is bigger than 255, such as 'eth266' */
|
|
if (atoi(name - (pos - letter_pos - 1)) > 255) {
|
|
return 0;
|
|
}
|
|
|
|
*let_pos = (u8_t)letter_pos;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCSIFNAME(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
u8_t letter_pos = 0;
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
netif = netif_find(ifr->ifr_name);
|
|
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
} else if (netif->link_layer_type == LOOPBACK_IF) {
|
|
return EPERM;
|
|
} else if ((netif->flags & IFF_UP) != 0) {
|
|
return EBUSY;
|
|
} else {
|
|
if (strncmp(ifr->ifr_name, ifr->ifr_newname, IFNAMSIZ) == 0) {
|
|
/* not change */
|
|
return 0;
|
|
}
|
|
|
|
ifr->ifr_newname[IFNAMSIZ - 1] = '\0';
|
|
if ((lwip_validate_ifname(ifr->ifr_newname, &letter_pos) == 0) || (strlen(ifr->ifr_newname) > (IFNAMSIZ - 1))) {
|
|
return EINVAL;
|
|
}
|
|
|
|
if (strncpy_s(netif->full_name, sizeof(netif->full_name), ifr->ifr_newname, strlen(ifr->ifr_newname)) != EOK) {
|
|
return EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIFINDEX(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
} else {
|
|
ifr->ifr_ifindex = netif_get_index(netif);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCSIFMTU(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
/* set netif hw addr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
}
|
|
#if LWIP_HAVE_LOOPIF
|
|
/* the mtu of loopif is not used. */
|
|
else if (netif->link_layer_type == LOOPBACK_IF) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
else {
|
|
if (ERR_OK != netif_set_mtu(netif, (u16_t)ifr->ifr_mtu)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIFMTU(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
|
|
/* get netif hw addr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
} else {
|
|
ifr->ifr_mtu = netif->mtu;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIFBRDADDR(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif = NULL;
|
|
struct sockaddr_in *sock_in = NULL;
|
|
|
|
/* get netif subnet broadcast addr */
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
}
|
|
if (ip4_addr_isany_val(*(ip_2_ip4(&netif->netmask)))) {
|
|
return ENXIO;
|
|
}
|
|
sock_in = (struct sockaddr_in *)&ifr->ifr_addr;
|
|
sock_in->sin_family = AF_INET;
|
|
sock_in->sin_addr.s_addr = (ip_2_ip4(&((netif)->ip_addr))->addr | ~(ip_2_ip4(&netif->netmask)->addr));
|
|
return 0;
|
|
}
|
|
|
|
#endif /* LWIP_IOCTL_IF */
|
|
|
|
#if LWIP_NETIF_ETHTOOL
|
|
|
|
static s32_t lwip_ioctl_internal_SIOCETHTOOL(struct ifreq *ifr)
|
|
{
|
|
struct netif *netif;
|
|
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
netif = netif_find(ifr->ifr_name);
|
|
if (netif == NULL) {
|
|
return ENODEV;
|
|
} else {
|
|
return dev_ethtool(netif, ifr);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
#if LWIP_IPV6
|
|
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCSIPV6DAD(struct ifreq *ifr)
|
|
{
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
struct netif *tmpnetif = netif_find(ifr->ifr_name);
|
|
if (tmpnetif == NULL) {
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
|
|
return ENODEV;
|
|
}
|
|
|
|
if ((ifr->ifr_ifru.ifru_ivalue != 0) && (ifr->ifr_ifru.ifru_ivalue != 1)) {
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("Invalid ioctl argument(ifru_ivalue 0/1).\n"));
|
|
return EBADRQC;
|
|
}
|
|
|
|
if (ifr->ifr_ifru.ifru_ivalue == 1) {
|
|
tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags | LWIP_IPV6_ND6_FLAG_DAD);
|
|
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("DAD turned on through ioctl for %s iface index %u \n",
|
|
tmpnetif->name, tmpnetif->num));
|
|
} else {
|
|
tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags & ((~LWIP_IPV6_ND6_FLAG_DAD) & 0xffU));
|
|
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("DAD turned off through ioctl for %s iface index %u \n",
|
|
tmpnetif->name, tmpnetif->num));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIPV6DAD(struct ifreq *ifr)
|
|
{
|
|
struct netif *tmpnetif = netif_find(ifr->ifr_name);
|
|
if (tmpnetif == NULL) {
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
|
|
return ENODEV;
|
|
}
|
|
ifr->ifr_ifru.ifru_ivalue = (tmpnetif->ipv6_flags & LWIP_IPV6_ND6_FLAG_DAD) ? 1 : 0;
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if LWIP_IOCTL_IPV6DPCTD
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCSIPV6DPCTD(struct ifreq *ifr)
|
|
{
|
|
#if LWIP_ENABLE_NET_CAPABILITY
|
|
if (!IsCapPermit(CAP_NET_ADMIN)) {
|
|
return EPERM;
|
|
}
|
|
#endif
|
|
|
|
struct netif *tmpnetif = netif_find(ifr->ifr_name);
|
|
if (tmpnetif == NULL) {
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
|
|
return ENODEV;
|
|
}
|
|
if ((ifr->ifr_ifru.ifru_ivalue != 0) && (ifr->ifr_ifru.ifru_ivalue != 1)) {
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("Invalid ioctl argument(ifru_ivalue 0/1).\n"));
|
|
return EBADRQC;
|
|
}
|
|
if (ifr->ifr_ifru.ifru_ivalue == 1) {
|
|
tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags | LWIP_IPV6_ND6_FLAG_DEPRECATED);
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("Deprecation turned on through ioctl for %s iface index %u \n",
|
|
tmpnetif->name, tmpnetif->num));
|
|
} else {
|
|
tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags & ((~LWIP_IPV6_ND6_FLAG_DEPRECATED) & 0xffU));
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("Deprecation turned off through ioctl for %s iface index %u \n",
|
|
tmpnetif->name, tmpnetif->num));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static u8_t lwip_ioctl_internal_SIOCGIPV6DPCTD(struct ifreq *ifr)
|
|
{
|
|
struct netif *tmpnetif = netif_find(ifr->ifr_name);
|
|
if (tmpnetif == NULL) {
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
|
|
return ENODEV;
|
|
}
|
|
|
|
ifr->ifr_ifru.ifru_ivalue = (tmpnetif->ipv6_flags & LWIP_IPV6_ND6_FLAG_DEPRECATED) ? 1 : 0;
|
|
return 0;
|
|
}
|
|
|
|
#endif /* LWIP_IOCTL_IPV6DPCTD */
|
|
#endif
|
|
|
|
static u8_t lwip_ioctl_impl(const struct lwip_sock *sock, long cmd, void *argp)
|
|
{
|
|
u8_t err = 0;
|
|
#if LWIP_NETIF_ETHTOOL
|
|
s32_t ret;
|
|
#endif
|
|
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_IF || LWIP_NETIF_ETHTOOL
|
|
struct ifreq *ifr = (struct ifreq *)argp;
|
|
#endif
|
|
#if LWIP_IOCTL_ROUTE
|
|
struct rtentry *rmten = (struct rtentry *)argp;
|
|
#endif
|
|
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_ROUTE || LWIP_IOCTL_IF
|
|
bool is_ipv6 = 0;
|
|
|
|
/* allow it only on IPv6 sockets... */
|
|
is_ipv6 = NETCONNTYPE_ISIPV6((unsigned int)(sock->conn->type));
|
|
#endif
|
|
|
|
switch ((u32_t)cmd) {
|
|
#if LWIP_IPV6
|
|
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
|
|
case SIOCSIPV6DAD:
|
|
/* allow it only on IPv6 sockets... */
|
|
if (is_ipv6 == 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCSIPV6DAD(ifr);
|
|
}
|
|
break;
|
|
case SIOCGIPV6DAD:
|
|
/* allow it only on IPv6 sockets... */
|
|
if (is_ipv6 == 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCGIPV6DAD(ifr);
|
|
}
|
|
break;
|
|
#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */
|
|
#if LWIP_IOCTL_IPV6DPCTD
|
|
case SIOCSIPV6DPCTD:
|
|
/* allow it only on IPv6 sockets... */
|
|
if (is_ipv6 == 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCSIPV6DPCTD(ifr);
|
|
}
|
|
break;
|
|
case SIOCGIPV6DPCTD:
|
|
/* allow it only on IPv6 sockets... */
|
|
if (is_ipv6 == 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCGIPV6DPCTD(ifr);
|
|
}
|
|
break;
|
|
#endif
|
|
#endif /* LWIP_IPV6 */
|
|
#if LWIP_IOCTL_ROUTE
|
|
case SIOCADDRT:
|
|
/* Do not allow if socket is AF_INET6 */
|
|
if (is_ipv6 != 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCADDRT(rmten);
|
|
}
|
|
break;
|
|
#endif
|
|
#if LWIP_IOCTL_IF
|
|
case SIOCGIFCONF:
|
|
/* Do not allow if socket is AF_INET6 */
|
|
if (is_ipv6 != 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCGIFCONF(ifr);
|
|
}
|
|
break;
|
|
case SIOCGIFADDR:
|
|
if (is_ipv6 != 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCGIFADDR(ifr);
|
|
}
|
|
break;
|
|
case SIOCSIFADDR:
|
|
if (is_ipv6 != 0) {
|
|
err = lwip_ioctl_internal_SIOCSIFADDR_6(ifr);
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCSIFADDR(ifr);
|
|
}
|
|
break;
|
|
case SIOCDIFADDR:
|
|
/* Delete interface address */
|
|
if (is_ipv6 != 0) {
|
|
err = lwip_ioctl_internal_SIOCDIFADDR_6(ifr);
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCDIFADDR(ifr);
|
|
}
|
|
break;
|
|
case SIOCGIFNETMASK:
|
|
if (is_ipv6 != 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCGIFNETMASK(ifr);
|
|
}
|
|
break;
|
|
case SIOCSIFNETMASK:
|
|
if (is_ipv6 != 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCSIFNETMASK(ifr);
|
|
}
|
|
break;
|
|
case SIOCSIFHWADDR:
|
|
err = lwip_ioctl_internal_SIOCSIFHWADDR(ifr);
|
|
break;
|
|
case SIOCGIFHWADDR:
|
|
err = lwip_ioctl_internal_SIOCGIFHWADDR(ifr);
|
|
break;
|
|
case SIOCSIFFLAGS:
|
|
err = lwip_ioctl_internal_SIOCSIFFLAGS(ifr);
|
|
break;
|
|
case SIOCGIFFLAGS:
|
|
err = lwip_ioctl_internal_SIOCGIFFLAGS(ifr);
|
|
break;
|
|
case SIOCGIFNAME:
|
|
err = lwip_ioctl_internal_SIOCGIFNAME(ifr);
|
|
break;
|
|
case SIOCSIFNAME:
|
|
err = lwip_ioctl_internal_SIOCSIFNAME(ifr);
|
|
break;
|
|
/* Need to support the get index through ioctl
|
|
* As of now the options is restricted to PF_PACKET scenario , so removed the compiler flag Begin
|
|
*/
|
|
case SIOCGIFINDEX:
|
|
err = lwip_ioctl_internal_SIOCGIFINDEX(ifr);
|
|
break;
|
|
case SIOCGIFMTU:
|
|
err = lwip_ioctl_internal_SIOCGIFMTU(ifr);
|
|
break;
|
|
case SIOCSIFMTU:
|
|
err = lwip_ioctl_internal_SIOCSIFMTU(ifr);
|
|
break;
|
|
case SIOCGIFBRDADDR:
|
|
if (is_ipv6 != 0) {
|
|
err = EINVAL;
|
|
} else {
|
|
err = lwip_ioctl_internal_SIOCGIFBRDADDR(ifr);
|
|
}
|
|
break;
|
|
#endif /* LWIP_IOCTL_IF */
|
|
#if LWIP_NETIF_ETHTOOL
|
|
case SIOCETHTOOL:
|
|
ret = lwip_ioctl_internal_SIOCETHTOOL(ifr);
|
|
if (ret != 0) {
|
|
/* an IO error happened */
|
|
err = EIO;
|
|
}
|
|
break;
|
|
#endif
|
|
/* START For cmd = -1 stack has to treat it as Invalid Input and return EINVAL */
|
|
case 0xFFFFFFFF:
|
|
err = EINVAL;
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl_impl(INVALID: 0x%lx)\n", cmd));
|
|
break;
|
|
default:
|
|
err = ENOSYS;
|
|
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(UNIMPL: 0x%lx)\n", cmd));
|
|
break;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static err_t lwip_do_ioctl_impl(struct tcpip_api_call_data *call)
|
|
{
|
|
struct lwip_ioctl_apimsg *msg = (struct lwip_ioctl_apimsg *)(void *)call;
|
|
return lwip_ioctl_impl(msg->sock, msg->cmd, msg->argp);
|
|
}
|
|
|
|
#include "los_vm_map.h"
|
|
#include "user_copy.h"
|
|
static int do_ioctl_SIOCGIFCONF(int sockfd, long cmd, void *argp)
|
|
{
|
|
int nbytes;
|
|
struct ifconf ifc;
|
|
char *buf_bak = NULL;
|
|
int ret;
|
|
|
|
if (LOS_ArchCopyFromUser(&ifc, argp, sizeof(struct ifconf)) != 0) {
|
|
set_errno(EFAULT);
|
|
return -1;
|
|
}
|
|
nbytes = ifc.ifc_len;
|
|
if (nbytes < 0) {
|
|
set_errno(EINVAL);
|
|
return -1;
|
|
}
|
|
buf_bak = ifc.ifc_buf;
|
|
if (!LOS_IsUserAddress((VADDR_T)(uintptr_t)buf_bak)) {
|
|
set_errno(EFAULT);
|
|
return -1;
|
|
}
|
|
ifc.ifc_buf = malloc(nbytes);
|
|
if (ifc.ifc_buf == NULL) {
|
|
set_errno(ENOMEM);
|
|
return -1;
|
|
}
|
|
(void)memset_s(ifc.ifc_buf, nbytes, 0, nbytes);
|
|
|
|
ret = lwip_ioctl(sockfd, cmd, &ifc);
|
|
if (ret == 0) {
|
|
if (LOS_ArchCopyToUser(buf_bak, ifc.ifc_buf, nbytes) != 0) {
|
|
set_errno(EFAULT);
|
|
ret = -1;
|
|
}
|
|
}
|
|
|
|
free(ifc.ifc_buf);
|
|
ifc.ifc_buf = buf_bak;
|
|
if (LOS_ArchCopyToUser(argp, &ifc, sizeof(struct ifconf)) != 0) {
|
|
set_errno(EFAULT);
|
|
ret = -1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int socks_ioctl(int sockfd, long cmd, void *argp)
|
|
{
|
|
void *argpbak = argp;
|
|
int ret;
|
|
size_t nbytes = 0;
|
|
|
|
if (LOS_IsUserAddress((VADDR_T)(uintptr_t)argp)) {
|
|
switch (cmd) {
|
|
case FIONREAD:
|
|
case FIONBIO:
|
|
nbytes = sizeof(int);
|
|
break;
|
|
case SIOCADDRT:
|
|
nbytes = sizeof(struct rtentry);
|
|
break;
|
|
case SIOCGIFCONF:
|
|
return do_ioctl_SIOCGIFCONF(sockfd, cmd, argp);
|
|
case SIOCSIPV6DAD:
|
|
case SIOCGIPV6DAD:
|
|
case SIOCSIPV6DPCTD:
|
|
case SIOCGIPV6DPCTD:
|
|
case SIOCGIFADDR:
|
|
case SIOCSIFADDR:
|
|
case SIOCDIFADDR:
|
|
case SIOCGIFNETMASK:
|
|
case SIOCSIFNETMASK:
|
|
case SIOCSIFHWADDR:
|
|
case SIOCGIFHWADDR:
|
|
case SIOCSIFFLAGS:
|
|
case SIOCGIFFLAGS:
|
|
case SIOCGIFNAME:
|
|
case SIOCSIFNAME:
|
|
case SIOCGIFINDEX:
|
|
case SIOCGIFMTU:
|
|
case SIOCSIFMTU:
|
|
case SIOCETHTOOL:
|
|
case SIOCGIFBRDADDR:
|
|
nbytes = sizeof(struct ifreq);
|
|
break;
|
|
default:
|
|
nbytes = 0;
|
|
}
|
|
if (argp != NULL && nbytes > 0) {
|
|
argp = malloc(nbytes);
|
|
if (argp == NULL) {
|
|
set_errno(ENOMEM);
|
|
return -1;
|
|
}
|
|
if (LOS_ArchCopyFromUser(argp, argpbak, nbytes) != 0) {
|
|
free(argp);
|
|
set_errno(EFAULT);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
ret = lwip_ioctl(sockfd, cmd, argp);
|
|
if (ret == 0 && argp != argpbak) {
|
|
if (LOS_ArchCopyToUser(argpbak, argp, nbytes) != 0) {
|
|
/* how to rollback ioctl ? */
|
|
set_errno(EFAULT);
|
|
ret = -1;
|
|
}
|
|
}
|
|
if (argp != argpbak) {
|
|
free(argp);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void socks_refer(int sockfd)
|
|
{
|
|
struct lwip_sock *sock = NULL;
|
|
SYS_ARCH_DECL_PROTECT(lev);
|
|
|
|
sock = get_socket(sockfd);
|
|
if (!sock) {
|
|
return;
|
|
}
|
|
|
|
SYS_ARCH_PROTECT(lev);
|
|
|
|
sock->s_refcount++;
|
|
|
|
SYS_ARCH_UNPROTECT(lev);
|
|
|
|
done_socket(sock);
|
|
}
|
|
|
|
int socks_close(int sockfd)
|
|
{
|
|
struct lwip_sock *sock = NULL;
|
|
SYS_ARCH_DECL_PROTECT(lev);
|
|
|
|
sock = get_socket(sockfd);
|
|
if (!sock) {
|
|
return -1;
|
|
}
|
|
|
|
SYS_ARCH_PROTECT(lev);
|
|
|
|
if (sock->s_refcount == 0) {
|
|
SYS_ARCH_UNPROTECT(lev);
|
|
done_socket(sock);
|
|
return lwip_close(sockfd);
|
|
}
|
|
|
|
sock->s_refcount--;
|
|
|
|
SYS_ARCH_UNPROTECT(lev);
|
|
done_socket(sock);
|
|
return 0;
|
|
}
|