Files
m241Neelima/components/ip_net2-6.9/ipnet2/src/ipnet_ioctl.c
T
2026-07-30 11:19:44 +05:30

2318 lines
72 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_ioctl.c,v $ $Revision: 1.248.10.27 $
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_ioctl.c,v $
* $Author: csun $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* ipcom_socketioctl() function.
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#define IPCOM_SKIP_NATIVE_SOCK_API
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include <ipnet_config.h>
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_err.h>
#include <ipcom_syslog.h>
#include "ipnet.h"
#include "ipnet_classifier.h"
#include "ipnet_h.h"
#include "ipnet_loopback.h"
#include "ipnet_route.h"
#include "ipnet_usr_sock.h"
#ifdef IPNET_USE_TUNNEL
#include "ipnet_tunnel.h"
#endif
#if defined(IPNET_USE_VLAN) || defined(IPNET_USE_VLAN_STACKING)
#include "ipnet_eth.h"
#endif
#ifdef IPNET_USE_VLAN_STACKING
#include "ipnet_svlan.h"
#endif
#ifdef IPNET_USE_PCAP
#include "ipnet_pcap.h"
#endif
#ifdef IPTCP
#include <iptcp.h>
#endif
#ifdef IPMPLS
#include <ipmpls.h>
#endif
#ifdef IPMIP4
#include <private/ipmip4_ipnet.h>
#endif
#ifdef IPIPSEC2
#include <ipipsec.h>
#include <ipipsec_pfkeyv2.h>
#endif
#ifdef IPCOM_WV_INSTRUMENTATION
#include <ipcom_windview.h>
#endif
#ifdef IPROHC
#include <iprohc.h>
#endif
#ifdef IPNET_USE_SECY
#include "ipmacsec.h"
#endif
#ifdef IPBRIDGE
#include "ipbridge.h"
#endif
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
struct Ipnet_ifconf_entry
{
char if_name[IP_IFNAMSIZ];
union ifconf_addr
{
struct Ip_sockaddr sa;
struct Ip_sockaddr_dl sdl;
struct Ip_sockaddr_in sin;
#ifdef IPCOM_USE_INET6
struct Ip_sockaddr_in6 sin6;
#endif
} s;
};
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
#ifdef IPIPSEC2
IP_GLOBAL Ip_err ipipsec_conf_internal(Ip_tag *ctrl_tags);
IP_GLOBAL Ip_err ipipsec_ctrl_internal(Ip_tag *ctrl_tags);
IP_GLOBAL Ip_err ipipsec_sactrl_internal(Ipipsec_sa_handle *sah, Ip_tag *ctrl_tags);
#endif
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipnet_ioctl_sigalarm
*===========================================================================
* Description: Raises EINTR error on all socket owned by the task with PID
* equal to *ppid.
* Parameters: ppid - Points to the PID of the application to interrupt
* or IP_NULL if the EINTR should be cleared.
* Returns:
*
*/
IP_STATIC void
ipnet_ioctl_sigalarm(Ip_pid_t *ppid)
{
Ipnet_socket *sock;
int i;
Ip_pid_t pid;
if (ppid == IP_NULL)
pid = ipnet_get_effective_pid();
else
pid = *ppid;
for (i = 0; i < ipnet_conf_max_sockets; i++)
{
sock = ipnet->sockets[i];
if (sock != IP_NULL
&& sock->ipcom.pid == pid
&& (sock->ipcom.so_errno == 0 || sock->ipcom.so_errno == IP_ERRNO_EINTR))
{
if (ppid == IP_NULL)
sock->ipcom.so_errno = 0;
else
ipnet_sock_data_avail(sock, IP_ERRNO_EINTR, 0);
}
}
ipcom_free(ppid);
}
/*
*===========================================================================
* ipnet_ioctl_if_is_rt_affected
*===========================================================================
* Description: Checks if the specified route is affected when the interface
* change route table.
* Parameters: netif - The network interface.
* rt - The route to test.
* Returns: IP_TRUE - Route is affected.
* IP_FALSE - Route is not affected.
*
*/
IP_STATIC Ip_bool
ipnet_ioctl_if_is_rt_affected(Ipnet_netif *netif, Ipnet_route_entry *rt)
{
if (rt->netif == IP_NULL)
return IP_FALSE;
if (rt->netif->ipcom.ifindex == netif->ipcom.ifindex)
return IP_TRUE;
#ifdef IPCOM_USE_INET
if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET)
{
struct Ipnet_ipv4_key *ipv4_key = (struct Ipnet_ipv4_key *) rt->hdr.key;
if (ipnet_ip4_get_addr_type2(ipv4_key->addr.s_addr, netif) == IPNET_ADDR_TYPE_UNICAST)
return IP_TRUE;
}
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET6)
{
struct Ipnet_ipv6_key *ipv6_key = (struct Ipnet_ipv6_key *) rt->hdr.key;
if (ipnet_ip6_get_addr_type2(&ipv6_key->addr, netif) == IPNET_ADDR_TYPE_UNICAST
&& (ipnet_ip6_is_scoped_addr(&ipv6_key->addr) == IP_FALSE
|| ipv6_key->scope_id == ipnet_ip6_get_zone(netif->ipcom.ifindex,
&ipv6_key->addr)))
return IP_TRUE;
}
#endif /* IPCOM_USE_INET6 */
return IP_FALSE;
}
/*
*===========================================================================
* ipnet_ioctl_if_remove_routes
*===========================================================================
* Description: Removes all routes that uses the specified interface.
* Parameters: netif - The network interface.
* vr - The route table from which the routes should be removed.
* Returns:
*
*/
IP_STATIC void
ipnet_ioctl_if_remove_routes(Ipnet_netif *netif, Ip_u16 vr)
{
Ipnet_route_entry *current;
int domain[2] = { 0, 0 };
unsigned num_domains = 0;
unsigned i, t;
unsigned num_tables = 0;
Ip_u32 *table_ids;
#ifdef IPCOM_USE_INET
domain[num_domains++] = IP_AF_INET;
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
domain[num_domains++] = IP_AF_INET6;
#endif /* IPCOM_USE_INET */
if (ipnet_route_get_table_ids(vr, IP_NULL, &num_tables) < 0)
{
/* Can only happen if there is a bug in the code */
IP_PANIC();
return;
}
table_ids = ipcom_calloc(num_tables, sizeof(*table_ids));
if (table_ids == IP_NULL)
{
IP_PANIC2();
return;
}
if (ipnet_route_get_table_ids(vr, table_ids, &num_tables) < 0)
{
/* Can only happen if there is a bug in the code */
IP_PANIC();
goto out;
}
for (i = 0; i < num_domains; i++)
for (t = 0; t < num_tables; t++)
{
current = ipnet_route_first_entry(domain[i], vr, table_ids[t]);
while (current != IP_NULL)
{
if (ipnet_ioctl_if_is_rt_affected(netif, current) == IP_FALSE)
{
current = ipnet_route_next_entry(current);
continue;
}
(void)ipnet_route_delete2(domain[i],
vr,
IPNET_ROUTE_GET_TABLE(current->head),
current->hdr.key,
current->hdr.mask,
current->gateway,
current->netif->ipcom.ifindex,
0,
0,
IP_FALSE);
current = ipnet_route_first_entry(domain[i], vr, table_ids[t]);
}
}
out:
ipcom_free(table_ids);
}
/*
*===========================================================================
* ipnet_ioctl_if_queue
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_ioctl_if_queue(unsigned long request,
struct Ipnet_ifqueue *ifq,
Ipnet_netif *netif)
{
Ipnet_pkt_queue *q;
switch (request)
{
case IPNET_SIOCGIFQUEUE:
if (netif->snd_queue == IP_NULL)
{
ifq->ifq_id = IP_IFQ_ID_DEFAULT;
ifq->ifq_parent_id = IP_IFQ_ID_NONE;
ipcom_strncpy(ifq->ifq_type, "none", sizeof(ifq->ifq_type));
}
else
{
q = netif->snd_queue;
if (ifq->ifq_id != IP_IFQ_ID_NONE && ifq->ifq_id != q->id)
{
if (q->c_ops == IP_NULL)
return -IP_ERRNO_ESRCH;
q = q->c_ops->q_get(q, ifq->ifq_id);
if (q == IP_NULL)
return -IP_ERRNO_ESRCH;
}
ifq->ifq_id = q->id;
ifq->ifq_parent_id = q->parent_id;
ipcom_strncpy(ifq->ifq_type, q->type, sizeof(ifq->ifq_type));
q->dump(q, &ifq->ifq_data);
ifq->ifq_count = q->count(q);
}
break;
case IPNET_SIOCSIFQUEUE:
ipnet_if_clean_snd_queue(netif);
if (ipcom_strcmp(ifq->ifq_type, "none") == 0)
{
ipnet_pkt_queue_delete(netif->snd_queue);
netif->snd_queue = IP_NULL;
}
else
{
int ret;
ret = ipnet_pkt_queue_new(ifq, netif, &q);
if (ret < 0)
return ret;
}
break;
default:
IP_PANIC();
return -IP_ERRNO_EINVAL;
}
return 0;
}
/*
*===========================================================================
* ipnet_ioctl_if_queue_filter
*===========================================================================
* Description: Controls IPNET interface queue filters for classfull interface
* queues.
* Parameters: request - request code
* f - filter parameters
* netif - the interface the queue is installed at
* Returns:
*
*/
IP_STATIC int
ipnet_ioctl_if_queue_filter(unsigned long request,
struct Ipnet_ifqueue_filter *f,
Ipnet_netif *netif)
{
Ipnet_pkt_queue *q = netif->snd_queue;
Ipnet_pkt_queue *child_q;
if (q == IP_NULL || q->c_ops == IP_NULL)
{
IPCOM_LOG3(WARNING, "ioctl: Could not set filter since queue %s:%d at %s does not support that operation",
q ? q->type : "none", q ? q->id : 0, netif->ipcom.name);
return -IP_ERRNO_EINVAL;
}
q = q->c_ops->q_get(q, f->filter_queue_id);
if (q == IP_NULL)
{
IPCOM_LOG2(WARNING, "ioctl: did not find a queue with ID: %d at interface %s",
f->filter_queue_id, netif->ipcom.name);
return -IP_ERRNO_ESRCH;
}
if (q->c_ops == IP_NULL)
{
IPCOM_LOG3(WARNING, "ioctl: queue %s:%d at %s is not a container",
q->type, q->id, netif->ipcom.name);
return -IP_ERRNO_EINVAL;
}
switch (request)
{
case IPNET_SIOCXAIFQFILTER:
child_q = q->c_ops->q_get(q, f->filter_child_queue_id);
if (child_q == IP_NULL || child_q->parent_id != q->id)
{
IPCOM_LOG3(WARNING, "ioctl: queue %s:%d has no child with ID %d",
q->type, q->id, f->filter_child_queue_id);
return -IP_ERRNO_EINVAL;
}
return q->c_ops->f_insert(q, f->filter_id, &f->filter_rule, f->filter_child_queue_id);
case IPNET_SIOCXDIFQFILTER:
return q->c_ops->f_remove(q, f->filter_id);
default:
IP_PANIC();
break;
}
return -IP_ERRNO_EINVAL;
}
/*
*===========================================================================
* ipnet_ioctl_if_siocgifconf
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_ioctl_if_siocgifconf(Ipnet_socket *sock, struct Ip_ifconf *ifconf)
{
Ipnet_netif *netif;
int len, ifc_len;
Ip_u32 i;
struct Ipnet_ifconf_entry *entry;
entry = (struct Ipnet_ifconf_entry *)ifconf->ip_ifc_buf;
ifc_len = 0;
/*
* IPNET_NETIF_FOR_EACH_ON_VR sets netif to NULL after the for
* loop, this is a performance optimized defination
*/
/* coverity[result_independent_of_operands] */
IPNET_NETIF_FOR_EACH_ON_VR(netif, sock->vr_index, i)
{
/* sockaddr_dl */
len = sizeof(entry->if_name) + sizeof(struct Ip_sockaddr_dl);
if ((ifconf->ifc_len - ifc_len) < len)
break;
ifc_len += len;
ipcom_memset(entry, 0, (Ip_size_t)len);
ipcom_strcpy(entry->if_name, netif->ipcom.name);
IPCOM_SA_LEN_SET(&entry->s.sdl, sizeof(struct Ip_sockaddr_dl));
entry->s.sdl.sdl_family = IP_AF_LINK;
entry->s.sdl.sdl_index = (Ip_u16) netif->ipcom.ifindex;
entry->s.sdl.sdl_type = (Ip_u8) netif->ipcom.type;
switch (netif->ipcom.type)
{
#ifdef IPCOM_USE_ETHERNET
case IP_IFT_ETHER:
entry->s.sdl.sdl_type = IP_IFT_ETHER;
entry->s.sdl.sdl_alen = 6;
ipcom_memcpy(entry->s.sdl.sdl_data, netif->ipcom.link_addr, 6);
break;
#endif
#ifdef IPNET_USE_WLAN
case IP_IFT_IEEE80211:
entry->s.sdl.sdl_type = IP_IFT_IEEE80211;
entry->s.sdl.sdl_alen = 6;
ipcom_memcpy(entry->s.sdl.sdl_data, netif->ipcom.link_addr, 6);
break;
#endif
#ifdef IPNET_USE_VLAN
case IP_IFT_L2VLAN:
entry->s.sdl.sdl_type = IP_IFT_L2VLAN;
entry->s.sdl.sdl_alen = 6;
ipcom_memcpy(entry->s.sdl.sdl_data, netif->ipcom.link_addr, 6);
break;
#endif
default:
break;
}
entry = (struct Ipnet_ifconf_entry *)((char*)entry + len);
/* sockaddr_in */
#ifdef IPCOM_USE_INET
{
Ipnet_ip4_addr_entry *inet4_addr; /* List of IPv4 addresses */
for (inet4_addr = netif->inet4_addr_list; inet4_addr; inet4_addr = inet4_addr->next)
{
if (inet4_addr->type != IPNET_ADDR_TYPE_UNICAST)
continue;
len = sizeof(entry->if_name) + sizeof(struct Ip_sockaddr_in);
if ((ifconf->ifc_len - ifc_len) < len)
break;
/* Add the unicast address */
ifc_len += len;
ipcom_memset(entry, 0, (Ip_size_t)len);
ipcom_strcpy(entry->if_name, netif->ipcom.name);
entry->s.sin.sin_family = IP_AF_INET;
IPCOM_SA_LEN_SET(&entry->s.sin, sizeof(struct Ip_sockaddr_in));
entry->s.sin.sin_addr.s_addr = inet4_addr->ipaddr_n;
entry = (struct Ipnet_ifconf_entry *)((char*)entry + len);
}
}
#endif /* IPCOM_USE_INET */
/* sockaddr_in6 */
#ifdef IPCOM_USE_INET6
{
Ipnet_ip6_addr_entry *inet6_addr; /* List of IPv6 addresses */
for (inet6_addr = netif->inet6_addr_list; inet6_addr; inet6_addr = inet6_addr->next)
{
if (IP_IN6_IS_ADDR_MULTICAST(&inet6_addr->addr) || IP_BIT_ISSET(inet6_addr->flags, IPNET_IP6_ADDR_FLAG_ANYCAST))
continue;
len = sizeof(entry->if_name) + sizeof(struct Ip_sockaddr_in6);
if ((ifconf->ifc_len - ifc_len) < len)
break;
ifc_len += len;
ipcom_memset(entry, 0, (Ip_size_t)len);
ipcom_strcpy(entry->if_name, netif->ipcom.name);
entry->s.sin.sin_family = IP_AF_INET6;
IPCOM_SA_LEN_SET(&entry->s.sin6, sizeof(struct Ip_sockaddr_in6));
if(IP_IN6_IS_ADDR_LINK_LOCAL(&inet6_addr->addr))
entry->s.sin6.sin6_scope_id = netif->ipcom.ifindex;
ipcom_memcpy(&entry->s.sin6.sin6_addr, &inet6_addr->addr, sizeof(struct Ip_in6_addr));
entry = (struct Ipnet_ifconf_entry *)((char*)entry + len);
}
}
#endif /* IPCOM_USE_INET6 */
}
ifconf->ifc_len = ifc_len;
return 0;
}
/*
*===========================================================================
* ipnet_ioctl_rtab
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_ioctl_rtab(unsigned long request, void *argp)
{
Ip_u16 *vr_ptr = argp;
struct Ip_sioc_route_table *srt = argp;
int ret;
switch (request)
{
case IP_SIOCADDVR:
ret = ipnet_route_add_table(*vr_ptr, IPCOM_ROUTE_TABLE_DEFAULT, vr_ptr, IP_NULL);
return ret;
case IP_SIOCDELVR:
return ipnet_route_delete_vr(*vr_ptr);
case IP_SIOCADDROUTETAB:
return ipnet_route_add_table(srt->vr, srt->table, &srt->vr, &srt->table);
case IP_SIOCDELROUTETAB:
if (IPCOM_ROUTE_TABLE_IS_DEFAULT(srt->table))
{
IPCOM_LOG0(WARNING, "Use IP_SIOCDELVR to delete a virtual router");
return -IP_ERRNO_EACCES;
}
return ipnet_route_delete_table(srt->vr, srt->table);
#ifdef IPNET_USE_ROUTE_TABLE_NAMES
case IP_SIOCGETROUTETAB:
if (ipnet_route_vr_and_table_from_name(srt->name, &srt->vr, &srt->table) == 0)
return 0;
ret = ipnet_ioctl_rtab(IP_SIOCADDROUTETAB, srt);
if (ret < 0)
return ret;
return ipnet_ioctl_rtab(IP_SIOCSROUTETABNAME, srt);
case IP_SIOCSROUTETABNAME:
return ipnet_route_set_name(srt->vr, srt->table, srt->name);
case IP_SIOCGROUTETABNAME:
return ipnet_route_get_name(srt->vr, srt->table, srt->name) == IP_NULL ? -IP_ERRNO_ESRCH : 0;
#endif /* IPNET_USE_ROUTE_TABLE_NAMES */
default:
return - IP_ERRNO_EINVAL;
}
}
/*
*===========================================================================
* ipnet_register_if_attach_handler
*===========================================================================
* Description: Registers a new network interface attach handler.
* Parameters: f - function that knows how to attach network interfaces
* Returns:
*
*/
IP_GLOBAL void
ipnet_register_if_attach_handler(Ipnet_if_attach_handler f)
{
ipnet->if_attach_handler = f;
}
/*
*===========================================================================
* ipnet_ioctl_if_attach
*===========================================================================
* Description:
* Parameters: ifreq -
* Returns:
*
*/
IP_STATIC int
ipnet_ioctl_if_attach(struct Ip_ifreq *ifreq)
{
if (ipnet->if_attach_handler)
return ipnet->if_attach_handler(ifreq->ifr_name,
ifreq->ifr_ifru.ifru_newname);
return -IP_ERRNO_EOPNOTSUPP;
}
/*
*===========================================================================
* ipnet_ioctl_if
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_ioctl_if(Ipnet_socket *sock, unsigned long request, struct Ip_ifreq *ifreq)
{
Ipnet_netif *netif;
int ret = 0;
if (request != IP_SIOCGIFCONF)
{
ip_assert(IP_IOCPARM_LEN(request) >= IP_IFNAMSIZ);
/* Ensure that the interface name is terminated */
ifreq->ifr_name[IP_IFNAMSIZ-1] = '\0';
}
switch (request)
{
case IP_SIOCSIFNAME:
case IP_SIOCSIFHWBROADCAST:
return -IP_ERRNO_EPERM;
case IP_SIOCGIFCONF:
return ipnet_ioctl_if_siocgifconf(sock, (struct Ip_ifconf *)ifreq);
case IP_SIOCIFCREATE:
case IP_SIOCXATTACH:
if (ipnet_if_nametonetif(sock->vr_index, ifreq->ifr_name))
return -IP_ERRNO_EEXIST;
if (request == IP_SIOCXATTACH)
return ipnet_ioctl_if_attach(ifreq);
#ifdef IPNET_USE_LOOPBACK
if (ipcom_strncmp(ifreq->ifr_name, "lo", 2) == 0)
{
ret = ipnet_loopback_attach(sock->vr_index, ifreq->ifr_name);
return ret;
}
#endif
#ifdef IPNET_USE_VLAN
if (ipcom_strncmp(ifreq->ifr_name, "vlan", 4) == 0)
return ipnet_vlan_create(sock, ifreq);
if (ipcom_strchr(ifreq->ifr_name, '.') != IP_NULL)
return ipnet_vlan_compact_create(sock, ifreq);
#endif
#ifdef IPPPP
#ifdef IPPPP_USE_PPPOE
if (ipcom_strncmp(ifreq->ifr_name, "pppoe", 5) == 0)
{
if (ipnet->ppp.pppoe_create == IP_NULL)
return -IP_ERRNO_EINVAL;
ifreq->ip_ifr_vr = sock->vr_index;
return ipnet->ppp.pppoe_create(ifreq);
}
#endif
#ifdef IPPPP_USE_PPPL2TP
if (ipcom_strncmp(ifreq->ifr_name, "pppl2tp", 7) == 0)
{
if (ipnet->ppp.pppl2tp_create == IP_NULL)
return -IP_ERRNO_EINVAL;
return ipnet->ppp.pppl2tp_create(ifreq);
}
#endif
if (ipcom_strncmp(ifreq->ifr_name, "ppp", 3) == 0)
{
if (ipnet->ppp.if_create == IP_NULL)
return -IP_ERRNO_EINVAL;
return ipnet->ppp.if_create(ifreq);
}
#endif
#ifdef IPNET_USE_TUNNEL
return ipnet_tunnel_create_bsd(sock, ifreq);
#else
return -IP_ERRNO_EINVAL;
#endif
case IP_X_SIOCADDTUNNEL:
#ifdef IPNET_USE_TUNNEL
/**/
return ipnet_tunnel_create_linux(sock, ifreq);
#else
return -IP_ERRNO_EINVAL;
#endif
case IP_SIOCGIFNAME:
netif = ipnet_if_indextonetif(sock->vr_index, (Ip_u32) ifreq->ifr_ifru.ifru_ifindex);
if (netif == IP_NULL)
return -IP_ERRNO_ENXIO;
ipcom_strncpy(ifreq->ifr_name, netif->ipcom.name, sizeof(ifreq->ifr_name));
return ret;
default:
break;
}
netif = ipnet_if_nametonetif(sock->vr_index, ifreq->ifr_name);
if (netif == IP_NULL)
return -IP_ERRNO_ENXIO;
switch (request)
{
case IP_SIOCGIFINDEX:
ifreq->ifr_ifru.ifru_ifindex = (int) netif->ipcom.ifindex;
break;
case IP_SIOCGIFMTU:
ifreq->ifr_ifru.ifru_mtu = (int)netif->ipcom.mtu;
break;
case IP_SIOCSIFMTU:
ret = ipnet_if_link_ioctl(netif, (Ip_u32) request, ifreq);
if (ret == 0
|| ret == -IP_ERRNO_EOPNOTSUPP
|| ret == -IP_ERRNO_EINVAL)
{
/*
* ioctl either successful, or not supported by the link
* layer (IP_ERRNO_EOPNOTSUPP) or by the driver
* (IP_ERRNO_EINVAL). The 2 errors are accepted since that
* is how setting the MTU used to work, i.e. no
* notification to the driver at all.
* The driver has to be notifed on VxWorks to enable
* Ethernet jumbograms (9k frames).
*/
netif->ipcom.mtu = (Ip_u32) ifreq->ifr_ifru.ifru_mtu;
#ifdef IPBRIDGE
(void)ipbridge_mtu_change_notify(netif);
#endif
ret = 0;
}
ipnet_if_update_mib2_ifLastChange(netif);
break;
case IP_SIOCGIFFLAGS:
ifreq->ifr_ifru.ifru_flags = (Ip_u16)netif->ipcom.flags;
break;
#ifdef IP_PORT_LKM
case IP_X_SIOCGIFLINKFLAGS:
/* LKM/LAS specific ioctl used for setting the link 0|1|2 flags */
{
Ip_u32 link_flags = netif->ipcom.flags;
link_flags &= IP_IFF_LINK0 | IP_IFF_LINK1 | IP_IFF_LINK2;
ifreq->ifr_ifru.ifru_flags = (Ip_u16)(link_flags >> 16);
}
break;
#endif
#ifdef IPCOM_USE_HW_CAPS
case IP_SIOCGIFCAP:
ifreq->ip_ifr_reqcap = 0; /* currently not supported */
ifreq->ip_ifr_curcap = netif->ipcom.drv_capabilities;
break;
#endif /* IPCOM_USE_HW_CAPS */
case IP_SIOCGIFMETRIC:
ifreq->ifr_ifru.ifru_metric = (int) netif->ipcom.metric;
break;
case IP_SIOCSIFMETRIC:
netif->ipcom.metric = (Ip_u32) ifreq->ifr_ifru.ifru_metric;
ipnet_if_update_mib2_ifLastChange(netif);
break;
case IP_SIOCSIFVR:
ret = ipnet_ioctl_move_if_rt_to_vr(netif, ifreq->ip_ifr_vr);
ipnet_if_update_mib2_ifLastChange(netif);
break;
case IP_SIOCGIFVR:
ifreq->ip_ifr_vr = netif->vr_index;
break;
case IP_SIOCSIFFLAGS:
ret = ipnet_netif_change_flags(&netif, ifreq->ifr_ifru.ifru_flags, 0);
ipnet_if_update_mib2_ifLastChange(netif);
break;
#ifdef IP_PORT_LKM
case IP_X_SIOCSIFLINKFLAGS:
/* LKM/LAS specific ioctl used for setting the link 0|1|2 flags */
{
Ip_u32 link_flags = ifreq->ifr_ifru.ifru_flags << 16;
link_flags &= IP_IFF_LINK0 | IP_IFF_LINK1 | IP_IFF_LINK2;
IP_BIT_CLR(netif->ipcom.flags, IP_IFF_LINK0 | IP_IFF_LINK1 | IP_IFF_LINK2);
IP_BIT_SET(netif->ipcom.flags, link_flags);
}
break;
#endif
case IPNET_SIOCGIFQUEUE:
case IPNET_SIOCSIFQUEUE:
return ipnet_ioctl_if_queue(request, (struct Ipnet_ifqueue *) ifreq, netif);
case IPNET_SIOCXAIFQFILTER:
case IPNET_SIOCXDIFQFILTER:
return ipnet_ioctl_if_queue_filter(request, (struct Ipnet_ifqueue_filter *) ifreq, netif);
case IP_SIOCXDETACH:
if (!ipnet_if_can_detach(&netif->ipcom))
return -IP_ERRNO_EBUSY;
/* Detach IPNET interface */
ret = ipnet_if_detach(netif);
if (ret < 0)
return ret;
/* Call link layer detach */
ret = ipnet_if_link_ioctl(netif, IP_SIOCXDETACH, IP_NULL);
/*
* One extra interface unlock is the same as calling
* ipcom_if_free(). This must be done regardless of what
* ipnet_if_link_ioctl() returns since the interface has
* already been detached from the stack.
*/
IPNET_IF_UNLOCK(netif);
break;
case IP_SIOCXRESETSTAT:
ipcom_memset((Ip_u8 *) netif + ip_offsetof(Ipnet_netif, ipackets),
0,
ip_offsetof(Ipnet_netif, noproto) - ip_offsetof(Ipnet_netif, ipackets));
break;
case IP_SIOCXGDHCPRUNNING:
ifreq->ifr_ifru.ifru_opt = IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_X_DHCPRUNNING) ? 1 : 0;
break;
case IP_SIOCXSDHCPRUNNING:
if (ifreq->ifr_ifru.ifru_opt == 1)
IP_BIT_SET(netif->ipcom.flags, IP_IFF_X_DHCPRUNNING);
else
IP_BIT_CLR(netif->ipcom.flags, IP_IFF_X_DHCPRUNNING);
ipnet_kioevent(netif, IP_EIOXCHANGE, IP_NULL, IP_FLAG_FC_STACKCONTEXT);
break;
#ifdef IPNET_USE_PCAP
case IP_SIOCXPCAP:
return ipnet_pcap_ioctl(netif, (Ip_u32) request, ifreq);
#endif
case IP_SIOCGIFTXQLEN:
#if !defined(IP_PORT_LKM)
ifreq->ifr_ifru.ifru_ivalue = 0;
break;
#endif
case IP_SIOCSIFTXQLEN:
return -IP_ERRNO_EPERM;
#ifdef IPNET_USE_VLAN_STACKING
case IP_SIOCSETVLANPVID:
case IP_SIOCSETVLANP:
case IP_SIOCDELVLANP:
case IP_SIOCSETVLANPRIMAP:
case IP_SIOCSETVLANINRULE:
case IP_SIOCSETVLANOUTRULE:
case IP_SIOCGETPVLAN:
return ipnet_vlan_stacking_ioctl(request, ifreq, netif);
#endif /* IPNET_USE_VLAN_STACKING */
#ifdef IPNET_USE_SECY
case IP_SIOCXSECY:
if (netif->secy && netif->secy->ioctl)
ret = netif->secy->ioctl(netif, (Ip_u32)request, ifreq);
else
ret = -IP_ERRNO_EOPNOTSUPP;
break;
#endif
default:
/* Remaining ioctl()'s to to link layer (including ETH, PPP etc). */
ret = ipnet_if_link_ioctl(netif, (Ip_u32 )request, ifreq);
break;
}
return ret;
}
/*
*===========================================================================
* ipnet_ioctl_wlan
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
#ifdef IPCOM_USE_WLAN
IP_STATIC int
ipnet_ioctl_wlan(Ipnet_socket *sock, unsigned long request, struct Ip_ifreq *ifreq)
{
Ipcom_netif *netif;
IpcomWlanBssReq *bssreq;
IpcomWlanBss *bsslist;
int size;
IpcomWlanStatus ret;
int i;
netif = (Ipcom_netif *) ipnet_if_nametonetif(sock->vr_index, ifreq->ifr_name);
if (netif == IP_NULL || netif->wlan == IP_NULL)
return IP_ERRNO_ENODEV;
switch (request)
{
case IP_SIOCXGWLANLIST:
bssreq = (IpcomWlanBssReq *) ifreq->ip_ifr_data;
ret = ipcom_wlan_get_bsslist(netif, &bsslist, &size);
if (ret != IPCOM_WLAN_STATUS_SUCCESS)
return IPCOM_ERR_FAILED;
/* What about user/kernel space copying here? */
size = IP_MIN(size, IPCOM_WLAN_MAX_BSS);
for (i = 0; i < size; i++)
bssreq->bsslist[i] = bsslist[i];
bssreq->num_bss = size;
break;
default:
break;
}
}
#endif /* IPCOM_USE_WLAN */
/*
*===========================================================================
* ipcom_ioctl_length_of_all_pkts
*===========================================================================
* Description: Returns the sum of the length of all packets in the list.
* Parameters: head - the head of the packet list
* Returns:
*
*/
IP_STATIC int
ipcom_ioctl_length_of_all_pkts(const Ipcom_pkt *head)
{
int totlen = 0;
const Ipcom_pkt *pkt;
for (pkt = head; pkt != IP_NULL; pkt = pkt->next)
totlen += ipcom_pkt_get_length(pkt);
return totlen;
}
/*
*===========================================================================
* ipnet_ioctl_sock
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_ioctl_sock(Ipnet_socket *sock, unsigned long request, void *argp)
{
int *iargp = (int*) argp;
unsigned int *uargp = (unsigned int*) argp;
Ip_pid_t *pid;
switch (request)
{
case IP_SIOCSPGRP:
sock->ipcom.pid = *uargp;
break;
case IP_SIOCGPGRP:
*uargp = sock->ipcom.pid;
break;
case IP_FIONBIO:
if (*iargp)
IP_BIT_SET(sock->flags, IPNET_SOCKET_FLAG_NONBLOCKING);
else
IP_BIT_CLR(sock->flags, IPNET_SOCKET_FLAG_NONBLOCKING);
#ifdef IPNET_SOCK_SENDMSG_ASYNCHRONOUS_IN_NONBLOCK_MODE
/* FALL THROUGH */
#else
break;
#endif
case IP_SIOCSNDASYNC:
if (*iargp)
IP_BIT_SET(sock->flags, IPNET_SOCKET_FLAG_SENDMSG_ASYNCHRONOUS);
else
{
int oldflags = sock->flags;
IP_BIT_CLR(sock->flags, IPNET_SOCKET_FLAG_SENDMSG_ASYNCHRONOUS);
if (IP_BIT_ISSET(oldflags, IPNET_SOCKET_FLAG_SENDMSG_ASYNCHRONOUS))
ipnet_sock_make_next_sendmsg_synchronous(sock);
}
break;
case IP_X_FIOGNBIO:
*iargp = IP_BIT_ISSET(sock->flags, IPNET_SOCKET_FLAG_NONBLOCKING) ? 1 : 0;
break;
case IP_FIONREAD:
if (sock->proto != IP_IPPROTO_TCP)
{
/*
* Returns the size of the next pending datagram in the
* integer in bytes, or 0 when no datagram is pending.
*/
*iargp = ipcom_pkt_get_length(sock->rcv_head);
break;
}
/* fall through */
case IP_SIOCINQ:
/*
* Returns the total size of all queued packet.
*/
*iargp = ipcom_ioctl_length_of_all_pkts(sock->rcv_head);
break;
case IP_SIOCOUTQ:
*iargp = ipcom_atomic_get(&sock->snd_bytes);
break;
case IP_X_SIOCSINTR:
if (!sock->ipcom.pid)
{
return -IP_ERRNO_EINVAL;
}
pid = ipcom_malloc(sizeof(*pid));
if (!pid)
{
return -IP_ERRNO_ENOMEM;
}
*pid = sock->ipcom.pid;
if (ipnet_timeout_schedule((Ip_s64) *iargp * 1000,
(Ipnet_timeout_handler) ipnet_ioctl_sigalarm,
pid,
IP_NULL) != 0)
{
ipcom_free(pid);
return -IP_ERRNO_ENOMEM;
}
break;
case IP_X_SIOCGINTR:
ipnet_ioctl_sigalarm(IP_NULL);
break;
#ifdef IP_X_SIOCSDEBUG
case IP_X_SIOCSDEBUG:
ipnet->debug = *iargp;
break;
#endif
#ifdef IP_X_SIOCGDEBUG
case IP_X_SIOCGDEBUG:
*iargp = ipnet->debug;
break;
#endif
default:
return -IP_ERRNO_EINVAL;
}
return 0;
}
#ifdef IPCOM_USE_INET
/*
*===========================================================================
* ipnet_ioctl_netif_from_in_addr
*===========================================================================
* Description: Returns the interface for which
* Parameters: request - IP_SIOCADDRT or IP_SIOCDELRT for add or delete a
* IPv4 route.
* Returns: 0 = success, <0 = error
*
*/
IP_STATIC Ipnet_netif *
ipnet_ioctl_netif_from_in_addr(Ipnet_socket *sock, Ip_u32 in_addr_n, Ip_u32 in_mask_n)
{
Ip_u32 i;
Ipnet_ip4_addr_entry *addr;
Ipnet_netif *netif;
/*
* IPNET_NETIF_FOR_EACH_ON_VR sets netif to NULL after the for loop,
* this is a performance optimized definition
*/
/* coverity[result_independent_of_operands] */
IPNET_NETIF_FOR_EACH_ON_VR(netif, sock->vr_index, i)
{
for (addr = netif->inet4_addr_list; addr != IP_NULL; addr = addr->next)
{
if (((addr->ipaddr_n ^ in_addr_n) & in_mask_n) == 0)
return netif;
}
}
return IP_NULL;
}
/*
*===========================================================================
* ipnet_ioctl_ip4_bsd43_compat
*===========================================================================
* Description: Adds or deletes route. Provides compatibility with application
* that still uses the old BSD 4.3 API.
* Parameters: request - IP_SIOCADDRT or IP_SIOCDELRT for add or delete a
* IPv4 route.
* Returns: 0 = success, <0 = error
*
*/
IP_STATIC int
ipnet_ioctl_ip4_bsd43_compat(Ipnet_socket *sock, unsigned long request, struct Ip_ortentry *ort)
{
struct Ipnet_route_add_param param;
struct Ipnet_ipv4_key key;
struct Ipnet_ipv4_key mask;
struct Ipnet_ipv4_key gw;
Ipnet_route_entry *re;
struct Ip_sockaddr *del_gw = IP_NULL;
if (ort->rt_dst.sa_family != IP_AF_INET)
return -IP_ERRNO_EINVAL;
key.addr.s_addr = ((struct Ip_sockaddr_in *) &ort->rt_dst)->sin_addr.s_addr;
if (request == IP_SIOCDELRT && IP_BIT_ISSET(ort->rt_flags, IPNET_RTF_GATEWAY))
{
if (ort->rt_gateway.sa_family != IP_AF_INET)
return -IP_ERRNO_EINVAL;
del_gw = ((struct Ip_sockaddr *) &ort->rt_gateway);
}
mask.addr.s_addr = IP_NETMASK(key.addr.s_addr);
if (request == IP_SIOCDELRT)
return ipnet_route_delete2(IP_AF_INET,
sock->vr_index,
IPCOM_ROUTE_TABLE_DEFAULT,
&key,
&mask,
del_gw,
0,
ipnet_get_effective_pid(),
0,
IP_FALSE);
ipcom_memset(&param, 0, sizeof(param));
param.domain = IP_AF_INET;
param.table = IPCOM_ROUTE_TABLE_DEFAULT;
param.flags = ort->rt_flags;
param.vr = sock->vr_index;
if (IP_BIT_ISSET(param.flags, IPNET_RTF_GATEWAY))
{
if (ort->rt_gateway.sa_family != IP_AF_INET)
return -IP_ERRNO_EINVAL;
gw.addr.s_addr = ((struct Ip_sockaddr_in *) &ort->rt_gateway)->sin_addr.s_addr;
param.gateway = &ort->rt_gateway;
if (ipnet_route_raw_lookup(IP_AF_INET, sock->vr_index, IPCOM_ROUTE_TABLE_DEFAULT,
IPNET_RTL_FLAG_DONTCLONE, &gw, 0, 0, &re) < 0)
return -IP_ERRNO_ENETUNREACH;
if (IP_BIT_ISSET(re->netif->ipcom.flags, IP_IFF_LOOPBACK))
param.netif = ipnet_ioctl_netif_from_in_addr(sock, gw.addr.s_addr, 0xffffffff);
else
param.netif = re->netif;
}
else
{
/* Try to get the interface from the key */
param.netif = ipnet_ioctl_netif_from_in_addr(sock, key.addr.s_addr, mask.addr.s_addr);
}
param.key = &key;
if (IP_BIT_ISSET(param.flags, IPNET_RTF_HOST))
{
if (IP_BIT_ISFALSE(param.flags, IPNET_RTF_GATEWAY))
/* Must be link local host since no gateway was specified */
IP_BIT_SET(param.flags, IPNET_RTF_LLINFO);
}
else
{
param.netmask = &mask;
if (IP_BIT_ISFALSE(param.flags, IPNET_RTF_GATEWAY))
/* Must be link local net since no gateway was specified */
IP_BIT_SET(param.flags, IPNET_RTF_CLONING);
}
param.no_ref_count = IP_TRUE;
return ipnet_route_add(&param);
}
/*
*===========================================================================
* ipnet_ioctl_x_route
*===========================================================================
* Description: Adds or deletes route. Provides an API that is easily
* mappable to the one used in Linux.
* Parameters: request - IP_SIOCXADDRT or IP_SIOCXDELRT for add or delete a
* IPv4/Ipv6 route.
* Returns: 0 = success, <0 = error
*
*/
IP_STATIC int
ipnet_ioctl_x_route(Ipnet_socket *sock,
unsigned long request,
struct Ip_rtxmsg *rtmsg)
{
Ip_sa_family_t family = rtmsg->rt_dst.sa_family;
struct Ipnet_route_add_param param;
union Ipnet_route_key key;
union Ipnet_route_key mask;
ipcom_memset(&param, 0, sizeof(param));
ipcom_memset(&key, 0, sizeof(key));
ipcom_memset(&mask, 0, sizeof(mask));
/* Determine address family */
switch (family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
{
struct Ip_sockaddr_in *sin = (struct Ip_sockaddr_in*)&rtmsg->rt_dst;
ipcom_memcpy(&key.ipv4.addr, &sin->sin_addr, sizeof(struct Ip_in_addr));
}
break;
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
{
struct Ip_sockaddr_in6 *sin6 = (struct Ip_sockaddr_in6*)&rtmsg->rt_dst;
ipcom_memcpy(&key.ipv6.addr, &sin6->sin6_addr, sizeof(struct Ip_in6_addr));
if (IPCOM_IN6_IS_ADDR_SCOPED(&key.ipv6.addr))
key.ipv6.scope_id = rtmsg->rt_ifindex;
}
break;
#endif
default:
return -IP_ERRNO_EINVAL;
}
ipnet_route_create_mask(&mask, rtmsg->rt_dst_prefixlen);
param.domain = family;
param.vr = sock->vr_index;
param.netif = ipnet_if_indextonetif(sock->vr_index,
rtmsg->rt_ifindex);;
param.key = &key;
param.netmask = &mask;
param.flags = rtmsg->rt_flags;
param.no_ref_count = IP_TRUE;
if (IP_BIT_ISSET(param.flags, IPNET_RTF_GATEWAY))
param.gateway = &rtmsg->rt_gateway;
if (request == IP_SIOCXDELRT)
return ipnet_route_delete2(param.domain,
param.vr,
IPCOM_ROUTE_TABLE_DEFAULT,
param.key,
param.netmask,
param.gateway,
0,
ipnet_get_effective_pid(),
0,
IP_FALSE);
if (IP_BIT_ISSET(param.flags, IPNET_RTF_HOST))
{
if (IP_BIT_ISFALSE(param.flags, IPNET_RTF_GATEWAY))
/* Must be link local host since no gateway was specified */
IP_BIT_SET(param.flags, IPNET_RTF_LLINFO);
}
else
{
if (IP_BIT_ISFALSE(param.flags, IPNET_RTF_GATEWAY))
/* Must be link local net since no gateway was specified */
IP_BIT_SET(param.flags, IPNET_RTF_CLONING);
}
return ipnet_route_add(&param);
}
/*
*===========================================================================
* ipnet_ioctl_ip4
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_ioctl_ip4(Ipnet_socket *sock, unsigned long request, struct Ip_ifreq *ifreq)
{
Ipnet_netif *netif;
Ipnet_ip4_addr_entry *addr;
struct Ip_sockaddr_in *in_addr;
struct Ip_ifaliasreq *ifalias;
Ip_u32 ipaddr_n;
Ip_u32 netmask_n;
Ip_u32 subbrd_n;
int ret = 0;
Ip_u16 flags = 0;
struct Ip_sockaddr_dl dl;
Ip_u32 netaddr_n;
struct Ipnet_route_add_param param;
if (request == IP_SIOCADDRT || request == IP_SIOCDELRT)
return ipnet_ioctl_ip4_bsd43_compat(sock, request, (struct Ip_ortentry *) ifreq);
ip_assert(IP_IOCPARM_LEN(request) >= IP_IFNAMSIZ);
netif = ipnet_if_nametonetif(sock->vr_index, ifreq->ifr_name);
if (netif == IP_NULL)
return -IP_ERRNO_ENXIO;
#ifdef IPPPP
if (netif->ipcom.type == IP_IFT_PPP || netif->ipcom.type == IP_IFT_PPPOE)
/* PPP special case. */
return ipnet_if_link_ioctl(netif, (Ip_u32)request, ifreq);
#endif
ifalias = (struct Ip_ifaliasreq *)ifreq;
switch (request)
{
case IP_SIOCGIFADDR:
case IP_SIOCSIFADDR:
case IP_SIOCDIFADDR:
case IP_SIOCGIFBRDADDR:
case IP_SIOCSIFBRDADDR:
case IP_SIOCGIFNETMASK:
case IP_SIOCSIFNETMASK:
case IP_SIOCGIFDSTADDR:
case IP_SIOCSIFDSTADDR:
in_addr = (struct Ip_sockaddr_in *) &ifreq->ifr_ifru.ifru_addr;
break;
#ifdef IP_SIOCAHOMEADDR
case IP_SIOCAHOMEADDR:
#endif
case IP_SIOCAIFADDR:
in_addr = (struct Ip_sockaddr_in *) &ifalias->ifra_addr;
break;
default:
in_addr = IP_NULL;
break;
}
if (in_addr != IP_NULL && IP_BIT_ISSET(IP_IOCF_W, request))
{
#if defined(IPNET_COMPAT_OLDSOCK) && defined(IPCOM_USE_SA_LEN)
if (in_addr->sin_family == 0 && in_addr->sin_len < IP_AF_MAX)
((struct Ip_sockaddr *)in_addr)->sa_family = in_addr->sin_len;
((struct Ip_sockaddr *)in_addr)->sa_len = sizeof(struct Ip_sockaddr_in);
#endif
if (in_addr->sin_family != IP_AF_INET
|| IPCOM_SA_LEN_GET(in_addr) < sizeof(struct Ip_sockaddr_in))
return -IP_ERRNO_EINVAL;
}
/* Get interface primary IPv4 address. */
if (request != IP_SIOCDIFADDR)
{
addr = netif->inet4_addr_list;
if (addr != IP_NULL && addr->type != IPNET_ADDR_TYPE_UNICAST)
addr = IP_NULL;
}
else
{
addr = ipnet_ip4_get_addr_entry(in_addr->sin_addr.s_addr,
sock->vr_index,
netif);
if (addr == IP_NULL)
return -IP_ERRNO_EADDRNOTAVAIL;
}
if (addr != IP_NULL)
{
ipaddr_n = addr->ipaddr_n;
netmask_n = addr->netmask_n;
subbrd_n = (addr->ipaddr_n & addr->netmask_n) | ~addr->netmask_n;
}
else
{
ipaddr_n = 0;
netmask_n = 0;
subbrd_n = 0;
}
switch (request)
{
case IP_SIOCGIFADDR:
case IP_SIOCGIFBRDADDR:
case IP_SIOCGIFNETMASK:
case IP_SIOCGIFDSTADDR:
ipcom_memset(in_addr, 0, sizeof(struct Ip_sockaddr_in));
in_addr->sin_family = IP_AF_INET;
IPCOM_SA_LEN_SET(in_addr, sizeof(struct Ip_sockaddr_in));
break;
#ifdef IP_SIOCAHOMEADDR
case IP_SIOCAHOMEADDR:
#endif
case IP_SIOCAIFADDR:
netmask_n = ((struct Ip_sockaddr_in *)&ifalias->ifra_mask)->sin_addr.s_addr;
/* Fall though */
case IP_SIOCSIFADDR:
ipaddr_n = in_addr->sin_addr.s_addr;
break;
default:
break;
}
switch (request)
{
case IP_SIOCGIFADDR:
if (!ipaddr_n)
return -IP_ERRNO_EADDRNOTAVAIL;
in_addr->sin_addr.s_addr = ipaddr_n;
break;
case IP_SIOCGIFBRDADDR:
in_addr->sin_addr.s_addr = subbrd_n;
break;
case IP_SIOCGIFNETMASK:
in_addr->sin_addr.s_addr = netmask_n;
break;
case IP_SIOCSIFNETMASK:
if (addr == IP_NULL)
return -IP_ERRNO_EINVAL;
ret = ipnet_ip4_change_addr_mask(addr, in_addr->sin_addr.s_addr);
break;
case IP_SIOCSIFADDR:
netmask_n = IP_NETMASK(in_addr->sin_addr.s_addr);
/*Before remove the previous primary address,check the new primary address*/
if (ip_ntohl(netmask_n) < 0xfffffffe && ipaddr_n != IP_INADDR_ANY)
{
if ((in_addr->sin_addr.s_addr & ~netmask_n) == 0)
return -IP_ERRNO_EINVAL;
if ((in_addr->sin_addr.s_addr & ~netmask_n) == ~netmask_n)
return -IP_ERRNO_EINVAL;
}
if (addr != IP_NULL)
{
/* Remove the previous primary address */
ret = ipnet_ip4_remove_addr(netif, addr->ipaddr_n);
if (ret < 0)
return ret;
}
#ifdef IP_PORT_LKM
/*
* Setting the address 0.0.0.0 is interpreted
* as remove primary address on Linux.
*/
if (in_addr->sin_addr.s_addr == 0)
break;
#endif /*IP_PORT_LKM*/
flags |= IPNET_IP4_ADDR_FLAG_PRIMARY;
/* Fall through */
case IP_SIOCAIFADDR:
#ifdef IP_SIOCAHOMEADDR
case IP_SIOCAHOMEADDR:
if (request == IP_SIOCAHOMEADDR)
flags |= IPNET_IP4_ADDR_FLAG_HOMEADDRESS | IPNET_IP4_ADDR_FLAG_PREFERRED;
#endif
ret = ipnet_ip4_add_addr2(netif,
in_addr->sin_addr.s_addr,
netmask_n,
flags,
IP_IN_CLASSD(in_addr->sin_addr.s_addr) ? IPNET_ADDR_TYPE_MULTICAST : IPNET_ADDR_TYPE_UNICAST);
break;
case IP_SIOCSIFBRDADDR:
if (addr != IP_NULL && subbrd_n != in_addr->sin_addr.s_addr)
{
if (0 != (subbrd_n = ipnet_ip4_netif_get_subbrd(netif)))
{
/* Remove the old */
netaddr_n = subbrd_n;
(void) ipnet_route_delete2(IP_AF_INET,
netif->vr_index,
IPCOM_ROUTE_TABLE_DEFAULT,
&netaddr_n,
IP_NULL,
IP_NULL,
netif->ipcom.ifindex,
0,
0,
IP_FALSE);
ipnet_ip4_remove_addr(netif,subbrd_n);
}
/* Add the new broadcast address */
ipnet_ip4_add_addr(netif,
in_addr->sin_addr.s_addr,
0,
IP_FALSE,
IPNET_ADDR_TYPE_NETBROADCAST);
netmask_n = 0xffffffff;
/* Add the new network interface route */
ipcom_memset(&dl, 0, sizeof(struct Ip_sockaddr_dl));
IPCOM_SA_LEN_SET(&dl, sizeof(struct Ip_sockaddr_dl));
dl.sdl_family = IP_AF_LINK;
dl.sdl_index = (Ip_u16)netif->ipcom.ifindex;
dl.sdl_type = (Ip_u8)netif->ipcom.type;
ipcom_memset(&param, 0, sizeof(struct Ipnet_route_add_param));
param.domain = IP_AF_INET;
param.vr = netif->vr_index;
param.table = IPCOM_ROUTE_TABLE_DEFAULT;
param.netif = netif;
netaddr_n = in_addr->sin_addr.s_addr;
param.gateway = (struct Ip_sockaddr *)&dl;
param.key = &netaddr_n;
param.netmask = &netmask_n;
param.flags = IPNET_RTF_UP | IPNET_RTF_HOST | IPNET_RTF_DONE | IPNET_RTF_LLINFO | IPNET_RTF_PREF ;
ret = ipnet_route_add(&param);
}
else
return -IP_ERRNO_EINVAL;
break;
case IP_SIOCDIFADDR:
ret = ipnet_ip4_remove_addr(netif, in_addr->sin_addr.s_addr);
break;
default:
return ipnet_if_link_ioctl(netif, (Ip_u32) request, ifreq);
}
return ret;
}
#endif /* IPCOM_USE_INET */
/*
*===========================================================================
* ipnet_ioctl_ip6
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
#ifdef IPCOM_USE_INET6
IP_STATIC int
ipnet_ioctl_ip6(Ipnet_socket *sock, unsigned long request, void *data)
{
Ipnet_netif *netif;
struct Ip_in6_ifreq *ifreq = (struct Ip_in6_ifreq *) data;
struct Ip_in6_aliasreq *ifareq = (struct Ip_in6_aliasreq *) data;
Ip_u32 preferred_lifetime = IPCOM_ADDR_INFINITE;
Ip_u32 valid_lifetime = IPCOM_ADDR_INFINITE;
Ip_u32 flags = 0;
ip_assert(IP_IOCPARM_LEN(request) >= IP_IFNAMSIZ);
netif = ipnet_if_nametonetif(sock->vr_index, ifreq->ifr_name);
if (netif == IP_NULL)
return -IP_ERRNO_ENXIO;
#ifdef IPPPP
if (netif->ipcom.type == IP_IFT_PPP || netif->ipcom.type == IP_IFT_PPPOE)
/* PPP special case. */
return ipnet_if_link_ioctl(netif, request, ifreq);
#endif
/* Sanity check */
switch (request)
{
case IP_SIOCAIFADDR_IN6:
case IP_SIOCXGIFADDR_IN6:
if (ifareq->ifra_addr.sin6_family != IP_AF_INET6
|| IPCOM_SA_LEN_GET(&ifareq->ifra_addr) < sizeof(struct Ip_sockaddr_in6))
return -IP_ERRNO_EINVAL;
break;
case IP_SIOCDIFADDR_IN6:
case IP_SIOCGIFPREFIX_IN6:
case IP_SIOCGIFADDR_IN6:
if (ifreq->ifr_ifru.ifru_addr.sin6_family != IP_AF_INET6
|| IPCOM_SA_LEN_GET(&ifreq->ifr_ifru.ifru_addr) < sizeof(struct Ip_sockaddr_in6))
return -IP_ERRNO_EINVAL;
break;
case IP_SIOCGIFDSTADDR_IN6:
if (!IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_POINTOPOINT))
return -IP_ERRNO_EINVAL;
break;
default:
return -IP_ERRNO_EINVAL;
}
switch (request)
{
case IP_SIOCGIFADDR_IN6:
{
Ipnet_ip6_addr_entry *address = (Ipnet_ip6_addr_entry *)netif->inet6_addr_list;
if(address == IP_NULL
|| address->type != IPNET_ADDR_TYPE_UNICAST)
{
return -IP_ERRNO_EADDRNOTAVAIL;
}
else
{
ipcom_memcpy(&ifreq->ifr_ifru.ifru_addr.sin6_addr, &address->addr, sizeof(struct Ip_in6_addr));
return 0;
}
break;
}
case IP_SIOCAIFADDR_IN6:
{
Ip_u32 ifindex = netif->ipcom.ifindex;
int ret = 0;
if (IP_IN6_IS_ADDR_UNSPECIFIED(&ifareq->ifra_addr.sin6_addr))
return -IP_ERRNO_EINVAL;
if (IP_IN6_IS_ADDR_LOOPBACK(&ifareq->ifra_addr.sin6_addr)
&& (IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_LOOPBACK)))
return -IP_ERRNO_EINVAL;
if (ifareq->ifra_lifetime.ia6t_preferred != (Ip_time_t)IPCOM_ADDR_INFINITE)
preferred_lifetime = (Ip_u32) (ifareq->ifra_lifetime.ia6t_preferred - ipcom_time(IP_NULL));
if (ifareq->ifra_lifetime.ia6t_expire != (Ip_time_t)IPCOM_ADDR_INFINITE)
valid_lifetime = (Ip_u32) (ifareq->ifra_lifetime.ia6t_expire - ipcom_time(IP_NULL));
if (IP_BIT_ISTRUE(ifareq->ifra_flags, IP_IN6_IFF_TEMPORARY))
flags |= IPNET_IP6_ADDR_FLAG_TEMPORARY;
if (IP_BIT_ISTRUE(ifareq->ifra_flags, IP_IN6_IFF_TENTATIVE))
flags |= IPNET_IP6_ADDR_FLAG_TENTATIVE;
if (IP_BIT_ISTRUE(ifareq->ifra_flags, IP_IN6_IFF_HOMEADDRESS))
flags |= IPNET_IP6_ADDR_FLAG_HOMEADDRESS;
if (IP_BIT_ISTRUE(ifareq->ifra_flags, IP_IN6_IFF_AUTONOMOUS))
flags |= IPNET_IP6_ADDR_FLAG_AUTONOMOUS;
if (IP_BIT_ISTRUE(ifareq->ifra_flags, IP_IN6_IFF_ANYCAST))
flags |= IPNET_IP6_ADDR_FLAG_ANYCAST;
#ifdef IPNET_USE_RFC3971
if (IP_BIT_ISTRUE(ifareq->ifra_flags, IP_IN6_IFF_CGA))
flags |= IPNET_IP6_ADDR_FLAG_CGA;
#endif
ret = ipnet_ip6_add_addr(netif,
&ifareq->ifra_addr.sin6_addr,
flags,
preferred_lifetime, valid_lifetime,
ipcom_sockaddr_to_prefixlen((struct Ip_sockaddr *) &ifareq->ifra_prefixmask));
netif = ipnet_if_indextonetif(IPCOM_VR_ANY, ifindex);
/* Check if peer address specified */
if (ret == 0
&& netif != IP_NULL
&& ifareq->ifra_dstaddr.sin6_family == IP_AF_INET6
&& IPCOM_SA_LEN_GET(&ifareq->ifra_dstaddr) == sizeof(struct Ip_sockaddr_in6))
{
Ipnet_ppp_peer *peer = netif->private_data;
/* Check if interface supports it */
if (peer != IP_NULL)
ret = ipnet_if_set_ipv6_ppp_peer(peer, &ifareq->ifra_dstaddr.sin6_addr);
else
ret = -IP_ERRNO_EINVAL;
if (ret != 0)
(void)ipnet_ip6_remove_addr(netif, &ifareq->ifra_addr.sin6_addr);
}
return ret;
}
case IP_SIOCDIFADDR_IN6:
return ipnet_ip6_remove_addr(netif, &ifreq->ifr_ifru.ifru_addr.sin6_addr);
case IP_SIOCGIFDSTADDR_IN6:
return ipnet_if_link_ioctl(netif, IP_SIOCGIFDSTADDR_IN6, &ifreq->ifr_ifru.ifru_addr.sin6_addr);
case IP_SIOCXGIFADDR_IN6:
{
Ipnet_ip6_addr_entry *address = (Ipnet_ip6_addr_entry *)netif->inet6_addr_list;
while (address != IP_NULL)
{
if (IP_IN6_ARE_ADDR_EQUAL(&address->addr, &ifareq->ifra_addr.sin6_addr))
{
ifareq->ifra_flags = 0;
if (IP_BIT_ISSET(address->flags, IPNET_IP6_ADDR_FLAG_TEMPORARY))
ifareq->ifra_flags |= IP_IN6_IFF_TEMPORARY;
if (IP_BIT_ISSET(address->flags, IPNET_IP6_ADDR_FLAG_TENTATIVE))
ifareq->ifra_flags |= IP_IN6_IFF_TENTATIVE;
if (IP_BIT_ISSET(address->flags, IPNET_IP6_ADDR_FLAG_HOMEADDRESS))
ifareq->ifra_flags |= IP_IN6_IFF_HOMEADDRESS;
if (IP_BIT_ISSET(address->flags, IPNET_IP6_ADDR_FLAG_AUTONOMOUS))
ifareq->ifra_flags |= IP_IN6_IFF_AUTONOMOUS;
if (IP_BIT_ISSET(address->flags, IPNET_IP6_ADDR_FLAG_ANYCAST))
ifareq->ifra_flags |= IP_IN6_IFF_ANYCAST;
if (IP_BIT_ISSET(address->flags, IPNET_IP6_ADDR_FLAG_DEPRECATED))
ifareq->ifra_flags |= IP_IN6_IFF_DEPRECATED;
if (IP_BIT_ISSET(address->flags, IPNET_IP6_ADDR_FLAG_AUTOMATIC))
ifareq->ifra_flags |= IP_IN6_IFF_AUTOMATIC;
#ifdef IPNET_USE_RFC3971
if (IP_BIT_ISSET(address->flags, IPNET_IP6_ADDR_FLAG_CGA))
ifareq->ifra_flags |= IP_IN6_IFF_CGA;
#endif
ifareq->ifra_lifetime.ia6t_expire = address->expires_sec;
ifareq->ifra_lifetime.ia6t_preferred = address->preferred_sec;
ifareq->ifra_lifetime.ia6t_pltime = 0;
ifareq->ifra_lifetime.ia6t_vltime = 0;
ipcom_memset(&ifareq->ifra_prefixmask, 0, sizeof(ifareq->ifra_prefixmask));
ipnet_route_create_mask(&ifareq->ifra_prefixmask.sin6_addr, address->prefixlen);
return 0;
}
/* traverses the next address list */
address = (Ipnet_ip6_addr_entry *)address->next;
}
}
break;
case IP_SIOCGIFPREFIX_IN6:
{
Ipnet_ip6_addr_entry *address;
address = (Ipnet_ip6_addr_entry *)netif->inet6_addr_list;
while (address != IP_NULL)
{
if (IP_IN6_ARE_ADDR_EQUAL(&address->addr, &ifreq->ifr_ifru.ifru_addr.sin6_addr))
{
ifreq->ifr_ifru.ifru_prefixlen = address->prefixlen;
return (int) address->prefixlen;
}
/* traverses the next address list */
address = (Ipnet_ip6_addr_entry *)address->next;
}
}
break;
}
return -IP_ERRNO_EINVAL;
}
#endif /* IPCOM_USE_INET6 */
/*
*===========================================================================
* ipnet_socketioctl_may_flush_dst_cache
*===========================================================================
* Description: Checks if this specific operation affect any destination
* cache entries.
* Parameters: vr - virtual router index
* request - ioctl request
* Returns:
*
*/
IP_STATIC void
ipnet_ioctl_may_flush_dst_cache(Ip_u16 vr, unsigned long request)
{
switch (request)
{
case IP_SIOCSARP:
case IP_SIOCDARP:
case IP_SIOCPARP:
case IP_SIOCUARP:
case IP_SIOCSIFLLADDR:
case IP_SIOCXSDHCPRUNNING:
case IP_SIOCSIFPRIVATE:
case IP_SIOCXSECY:
case IP_SIOCXSIFFEVENTCB:
case IP_SIOCXDIFFEVENTCB:
case IP_SIOCSROUTETABNAME:
case IP_SIOCSETVLAN:
case IP_SIOCSETVLANP:
case IP_SIOCDELVLANP:
case IP_SIOCSETVLANPVID:
case IP_SIOCSETVLANPRIMAP:
case IP_SIOCSETVLANINRULE:
case IP_SIOCSETVLANOUTRULE:
case IP_SIOCXRESETSTAT:
case IP_SIOCXPCAP:
case IP_SIOCSROHCSTATUS:
case IP_SIOCSROHCCID:
case IP_SIOCSETSTPID:
case IP_SIOCADDMULTI:
case IP_SIOCDELMULTI:
/*
* Cannot affect the destination cache
*/
break;
case IP_SIOCSIFADDR:
case IP_SIOCSIFBRDADDR:
case IP_SIOCSIFNETMASK:
case IP_SIOCSIFDSTADDR:
case IP_SIOCAIFADDR:
case IP_SIOCDIFADDR:
case IP_SIOCADDRT:
case IP_SIOCDELRT:
case IP_SIOCXADDRT:
case IP_SIOCXDELRT:
case IP_SIOCAHOMEADDR:
case IP_SIOCMIP4:
/*
* Can only affect AF_INET
*/
ipnet_dst_cache_flush(vr, IP_AF_INET);
break;
case IP_SIOCAIFADDR_IN6:
case IP_SIOCDIFADDR_IN6:
case IP_SIOCXSETGW_IN6:
/*
* Can only affect AF_INET6
*/
ipnet_dst_cache_flush(vr, IP_AF_INET6);
break;
default:
/*
* Play it safe for things by default, operation may affect
* existing entries in the destination cache...
*/
ipnet_dst_cache_flush(vr, 0);
break;
}
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipnet_ioctl_move_if_rt_to_vr
*===========================================================================
* Description: Moves all routes that are using the interface to the
* new routing table.
* Parameters: netif - The network interface that change route table.
* vr - New virtual router index.
* Returns: 0 = success, <0 = error code
*
*/
IP_GLOBAL int
ipnet_ioctl_move_if_rt_to_vr(Ipnet_netif *netif, Ip_u16 vr)
{
Ipnet_route_entry *rt;
struct Ipnet_route_add_param rt_add_param;
int n;
Ip_size_t d;
int domains[] = {
#ifdef IPCOM_USE_INET
IP_AF_INET,
#endif
#ifdef IPCOM_USE_INET6
IP_AF_INET6
#endif /* IPCOM_USE_INET */
};
if (vr == netif->vr_index)
/* The interface is already using the specified route table */
return 0;
if (ipnet_route_is_virtual_router_valid(vr) == IP_FALSE)
{
IPCOM_LOG2(WARNING, "%s cannot be assigned to virtual router %u since it does not exist",
netif->ipcom.name, vr);
return -IP_ERRNO_ENXIO;
}
#ifdef IP_PORT_LKM
/* Don't allow multiple interfaces with identical names in the same VR */
if (ipnet_if_nametonetif(vr, netif->ipcom.name) != IP_NULL)
return -IP_ERRNO_EPERM;
#endif /* IP_PORT_LKM */
/* Issue the change VR event */
IPNET_NETLINKSOCK(ipnet_netlinksock_vrtab_change(netif->vr_index, netif->ipcom.name, vr));
/* Copy all routes that uses this interface to the new route table
* Note: Two passes necessary because cloning routes need to be added first!
*/
for (d = 0; d < sizeof(domains) / sizeof(domains[0]); d++)
{
for (n = 0; n < 2; n++)
{
for (rt = ipnet_route_first_entry(domains[d], netif->vr_index, IPCOM_ROUTE_TABLE_DEFAULT);
rt != IP_NULL;
rt = ipnet_route_next_entry(rt))
{
int ret;
if (n == 0 && IP_BIT_ISFALSE(rt->hdr.flags, IPNET_RTF_CLONING))
continue;
if (n == 1 && IP_BIT_ISTRUE(rt->hdr.flags, IPNET_RTF_CLONING))
continue;
if (ipnet_ioctl_if_is_rt_affected(netif, rt) == IP_FALSE)
continue;
if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_X_MCAST_RO | IPNET_RTF_X_BCAST_RO))
{
rt->netif = IP_NULL;
IP_BIT_CLR(rt->hdr.flags, IPNET_RTF_UP);
continue;
}
ipcom_memset(&rt_add_param, 0, sizeof(rt_add_param));
rt_add_param.domain = domains[d];
rt_add_param.flags = rt->hdr.flags;
rt_add_param.gateway = rt->gateway;
rt_add_param.key = rt->hdr.key;
rt_add_param.metrics = &rt->metrics;
if (IP_BIT_ISSET(rt->netif->ipcom.flags, IP_IFF_LOOPBACK))
rt_add_param.netif = ipnet_loopback_get_netif(vr);
else
rt_add_param.netif = rt->netif;
rt_add_param.netmask = rt->hdr.mask;
rt_add_param.pid = rt->pid;
rt_add_param.seq = rt->seq;
rt_add_param.vr = vr;
rt_add_param.table = IPCOM_ROUTE_TABLE_DEFAULT;
if (IP_BIT_ISSET(rt_add_param.flags, IPNET_RTF_MASK))
{
int i;
for (i = 0; i < rt->ref_count; i++)
ret = ipnet_route_add(&rt_add_param);
}
else
ret = ipnet_route_add(&rt_add_param);
ip_assert2(ret == 0 || ret == -IP_ERRNO_EEXIST);
(void)ret;
}
}
}
/* Remove all route that are using this interface from the old route table */
ipnet_ioctl_if_remove_routes(netif, netif->vr_index);
#ifdef IPCOM_USE_INET
{
Ipnet_ip4_addr_entry *addr;
for (addr = netif->inet4_addr_list; addr != IP_NULL; addr = addr->next)
ipnet_ip4_remove_addr_cache(addr);
}
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
{
Ipnet_ip6_addr_entry *addr;
for (addr = netif->inet6_addr_list; addr != IP_NULL; addr = addr->next)
ipnet_ip6_remove_addr_cache(addr);
}
#endif /* IPCOM_USE_INET */
IPNET_NETLINKSOCK(ipnet_rtnetlink_link_delete(netif));
#ifdef IPNET_USE_FAST_IFNAME_LOOKUP
/* Remove from interface name hash table */
(void)ipcom_hash_remove(ipnet->ifname_tab,netif);
#endif /* IPNET_USE_IFNAME_LOOKUP */
/* Change the route tab */
netif->vr_index = vr;
#ifdef IPCOM_USE_INET
{
Ipnet_ip4_addr_entry *addr;
for (addr = netif->inet4_addr_list; addr != IP_NULL; addr = addr->next)
if (ipnet_ip4_insert_addr_cache(addr))
IP_PANIC();
}
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
{
Ipnet_ip6_addr_entry *addr;
for (addr = netif->inet6_addr_list; addr != IP_NULL; addr = addr->next)
if (ipnet_ip6_insert_addr_cache(addr))
IP_PANIC();
}
#endif /* IPCOM_USE_INET */
#ifdef IPNET_USE_FAST_IFNAME_LOOKUP
/* Update interface name hash table with new VR index */
(void)ipcom_hash_add(ipnet->ifname_tab, netif);
#endif /* IPNET_USE_FAST_IFNAME_LOOKUP */
IPNET_NETLINKSOCK(ipnet_rtnetlink_link_add(netif));
#ifdef IP_PORT_LKM
ipcom_netif_assign_vr(&netif->ipcom, netif->vr_index);
#endif /* IP_PORT_LKM */
return 0;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipnet_sys_socketioctl
*===========================================================================
* Description: IO control.
* Parameters: fd - A socket descriptor.
* request - The IO control request.
* argp - Request specific data.
* Returns: 0 = success, -1 = error (error code from ipcom_errno).
*
*/
IP_PUBLIC int
ipnet_sys_socketioctl(Ip_fd fd, unsigned long request, void *argp)
{
Ipnet_socket *sock;
Ipnet_sock_ops *ops;
int i;
/*
* This union is only used to avoid the gcc warning
* "dereferencing type-punned pointer will break strict-aliasing rules"
*/
union {
Ipcom_if_eventcb cb;
void *ptr;
} event_u;
IPNET_FD_TO_OPEN_SOCKET(fd, sock);
if (IP_BIT_ISSET(request, IP_IOCF_W))
{
/*
* Write operation, may change stack state.
*/
ipnet_sock_make_next_sendmsg_synchronous(sock);
ipnet_ioctl_may_flush_dst_cache(sock->vr_index, request);
}
ops = ipnet_sock_get_ops(sock);
if (ops->ioctl != IP_NULL)
{
i = ops->ioctl(sock, request, argp);
if (i == 0 || i != -IP_ERRNO_EOPNOTSUPP)
return i;
/* else: try the IPNET ioctl handlers */
}
switch (IP_IOC_GROUP(request))
{
case IP_IOCG_SOCK:
return ipnet_ioctl_sock(sock, request, argp);
case IP_IOCG_RTAB:
return ipnet_ioctl_rtab(request, argp);
case IP_IOCG_POLICY_RT:
return ipnet_route_policy_ioctl(ipnet_get_effective_pid(),
sock->vr_index,
(Ip_u32)request,
(struct Ipnet_policy_routing_rule *) argp);
case IP_IOCG_NETIF:
case IP_IOCG_ETH:
#ifdef IPPPP
case IP_IOCG_PPP:
#endif
#ifdef IPNET_USE_WLAN
case IP_IOCG_WLAN:
#endif
return ipnet_ioctl_if(sock, request, (struct Ip_ifreq *) argp);
#ifdef IPCOM_USE_INET
case IP_IOCG_INET:
return ipnet_ioctl_ip4(sock, request, (struct Ip_ifreq *) argp);
#ifdef IPNET_USE_MCAST_ROUTING
case IP_IOCG_MCAST:
return ipnet_ip4_mcast_ioctl(sock, request, argp);
#endif
#ifdef IPCOM_USE_ETHERNET
case IP_IOCG_ARP:
return ipnet_arp_ioctl(sock, request, (struct Ip_arpreq *) argp);
#endif
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
case IP_IOCG_INET6:
return ipnet_ioctl_ip6(sock, request, argp);
#ifdef IPNET_USE_MCAST_ROUTING
case IP_IOCG_MCAST_IN6:
return ipnet_ip6_mcast_ioctl(sock, request, argp);
#endif
#endif /* IPCOM_USE_INET6 */
#ifdef IPMPLS
case IP_IOCG_MPLS:
return ipmpls_ioctl(request, argp);
#endif
#ifdef IPNET_USE_DIFFSERV
case IP_IOCG_DS:
return ipnet_diffserv_ioctl((Ip_u32) request, argp);
#endif
default:
break;
}
switch (request)
{
#ifdef IPCOM_USE_INET6
case IP_SIOCXGETGW_IN6:
/* Get default IPv6 gateway. */
return -IP_ERRNO_ENOSUPPORT;
case IP_SIOCXSETGW_IN6:
{
/* Set default IPv6 gateway (including its optional scope id). */
struct Ipnet_route_add_param param;
struct Ipnet_ipv6_key rt6;
struct Ip_sockaddr_in6 gw6;
Ipnet_route_entry *rt;
ipcom_memset(&param, 0, sizeof(struct Ipnet_route_add_param));
ipcom_memset(&rt6, 0, sizeof(struct Ipnet_ipv6_key));
ipcom_memset(&gw6, 0, sizeof(gw6));
param.domain = IP_AF_INET6;
param.flags = IPNET_RTF_UP | IPNET_RTF_GATEWAY | IPNET_RTF_DONE | IPNET_RTF_STATIC;
/* Key == :: */
param.key = &rt6;
/* Netmask == /0 */
param.netmask = &rt6;
/* Gateway */
param.gateway = (struct Ip_sockaddr *)&gw6;
IPCOM_SA_LEN_SET(&gw6, sizeof(struct Ip_sockaddr_in6));
gw6.sin6_family = IP_AF_INET6;
ipcom_memcpy(&gw6.sin6_addr, &((struct Ip_sockaddr_in6 *)argp)->sin6_addr, sizeof(struct Ip_in6_addr));
gw6.sin6_scope_id = ((struct Ip_sockaddr_in6 *)argp)->sin6_scope_id;
if (ipnet_route_raw_lookup(IP_AF_INET6, sock->vr_index,
IPCOM_ROUTE_TABLE_DEFAULT, IPNET_RTL_FLAG_DONTCLONE,
&gw6.sin6_addr, gw6.sin6_scope_id, 0, &rt) < 0)
return -IP_ERRNO_ENETUNREACH;
ip_assert(rt);
ip_assert(rt->netif);
param.netif = rt->netif;
param.vr = sock->vr_index;
param.table = IPCOM_ROUTE_TABLE_DEFAULT;
return ipnet_route_add(&param);
}
#endif /* IPCOM_USE_INET6 */
case IP_SIOCXSIFFEVENTCB:
/* Set interface event callback. */
for (i = 0; i < IPNET_MAX_IF_EVENTCB; i++)
if (ipnet->if_eventcb[i] == IP_NULL)
{
event_u.ptr = argp;
ipnet->if_eventcb[i] = event_u.cb;
return 0;
}
return -IP_ERRNO_EINVAL;
case IP_SIOCXDIFFEVENTCB:
/* Delete interface event callback. */
event_u.ptr = argp;
for (i = 0; i < IPNET_MAX_IF_EVENTCB; i++)
if (ipnet->if_eventcb[i] == event_u.cb)
{
ipnet->if_eventcb[i] = IP_NULL;
return 0;
}
return -IP_ERRNO_ENOENT;
#ifdef IPIPSEC2
case IP_SIOCXIPSEC_SELECTOR:
case IP_SIOCXIPSEC_NEXT_SA:
case IP_SIOCXIPSEC_Grouped:
case IP_SIOCXIPSEC_InUserOctets:
case IP_SIOCXIPSEC_OutUserOctets:
case IP_SIOCXIPSEC_InUserPackets:
case IP_SIOCXIPSEC_OutUserPackets:
return ipipsec_sys_ioctl(fd, request, argp);
#ifdef IPIPSEC_USE_CTRL_API
case IP_SIOCXIPSEC_CTL:
return ipipsec_ctrl_internal(((Ip_tag **)argp)[0]);
case IP_SIOCXIPSEC_SA_CTL:
return ipipsec_sactrl_internal(((void **)argp)[0], ((void **)argp)[1]);
case IP_SIOCXIPSEC_CONF_CTL:
return ipipsec_conf_internal(((void **)argp)[0]);
#endif
#endif /* IPIPSEC2 */
#ifdef IPCOM_USE_INET
case IP_SIOCXADDRT:
case IP_SIOCXDELRT:
return ipnet_ioctl_x_route(sock, request, argp);
#endif /* IPCOM_USE_INET */
#ifdef IPROHC
case IP_SIOCSROHCSTATUS:
case IP_SIOCROHCADDIF:
case IP_SIOCROHCDELIF:
case IP_SIOCROHCADDIFPROFILE:
case IP_SIOCROHCDELIFPROFILE:
case IP_SIOCSROHCCID:
return iprohc_ioctl(request, (struct Ip_rohcreq *) argp);
#endif /* IPROHC */
#ifdef IPNET_USE_VLAN_STACKING
case IP_SIOCSETSTPID:
case IP_SIOCGETSTPID:
return ipnet_vlan_stacking_ioctl(request, argp, IP_NULL);
#endif /*IPNET_USE_VLAN_STACKING */
default:
break;
}
return -IP_ERRNO_EINVAL;
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/