1611 lines
52 KiB
C
1611 lines
52 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipnet_sysctl.c,v $ $Revision: 1.101.10.14 $
|
|
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_sysctl.c,v $
|
|
* $Author: lwang7 $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#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_cstyle.h>
|
|
#include <ipcom_heap_sort.h>
|
|
#include <ipcom_route.h>
|
|
#include <ipcom_sysctl.h>
|
|
#include <ipcom_type.h>
|
|
|
|
#include "ipnet.h"
|
|
#include "ipnet_h.h"
|
|
#include "ipnet_route.h"
|
|
#include "ipnet_routesock.h"
|
|
#include "ipnet_signal.h"
|
|
#include "ipnet_usr_sock.h"
|
|
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Used when dumping routes to keep the state and buffers
|
|
*/
|
|
typedef struct Ipnet_sysctl_route_data_struct
|
|
{
|
|
void *buf;
|
|
Ip_size_t buf_len;
|
|
|
|
/*
|
|
* Total number of bytes written.
|
|
*/
|
|
Ip_size_t bytes_written;
|
|
|
|
/*
|
|
* The current route message being created
|
|
*/
|
|
struct Ipnet_rt_msghdr *rtm;
|
|
Ip_u32 flags;
|
|
Ip_u16 vr;
|
|
Ip_u32 table;
|
|
int soerrno;
|
|
int domain;
|
|
}
|
|
Ipnet_sysctl_route_data;
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_route_add_addr
|
|
*===========================================================================
|
|
* Description: Adds an address in route table format.
|
|
* Parameters: buf - the buffer to where the address should be written.
|
|
* domain - the domain this address is part of.
|
|
* rt_addr - a address or mask from the route table.
|
|
* Returns: The address to where the next data should be written in
|
|
* the buffer.
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_sysctl_fill_route_addr(void *buf, int domain, void *rt_addr)
|
|
{
|
|
union Ip_sockaddr_union *addr;
|
|
|
|
if (buf == IP_NULL)
|
|
return;
|
|
|
|
addr = (union Ip_sockaddr_union *) buf;
|
|
#ifdef IPCOM_USE_INET
|
|
if (domain == IP_AF_INET)
|
|
{
|
|
struct Ipnet_ipv4_key *key = (struct Ipnet_ipv4_key *) rt_addr;
|
|
|
|
ipcom_memset(addr, 0, sizeof(struct Ip_sockaddr_in));
|
|
addr->sin.sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(&addr->sin, sizeof(struct Ip_sockaddr_in));
|
|
ipcom_memcpy(&addr->sin.sin_addr, &key->addr, sizeof(addr->sin.sin_addr));
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
#ifdef IPCOM_USE_INET6
|
|
if (domain == IP_AF_INET6)
|
|
{
|
|
struct Ipnet_ipv6_key *key = (struct Ipnet_ipv6_key *) rt_addr;
|
|
|
|
ipcom_memset(addr, 0, sizeof(struct Ip_sockaddr_in6));
|
|
addr->sin6.sin6_family = IP_AF_INET6;
|
|
IPCOM_SA_LEN_SET(&addr->sin6, sizeof(struct Ip_sockaddr_in6));
|
|
ipcom_memcpy(&addr->sin6.sin6_scope_id, &key->scope_id, sizeof(addr->sin6.sin6_scope_id));
|
|
ipcom_memcpy(&addr->sin6.sin6_addr, &key->addr, sizeof(addr->sin6.sin6_addr));
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_push_rtm_data
|
|
*===========================================================================
|
|
* Description: Allocates space for a new data object which is payload
|
|
* in a route message.
|
|
* Parameters: d - dump context.
|
|
* len - length of the data object.
|
|
* Returns: A pointer to the beginning of the data area.
|
|
*
|
|
*/
|
|
IP_STATIC void *
|
|
ipnet_sysctl_push_rtm_data(Ipnet_sysctl_route_data *d, Ip_size_t len)
|
|
{
|
|
char *buf = d->buf;
|
|
|
|
if (d->rtm != IP_NULL)
|
|
d->rtm->rtm_msglen = (Ip_u16)(d->rtm->rtm_msglen + len);
|
|
|
|
d->bytes_written += len;
|
|
if (d->bytes_written > d->buf_len)
|
|
{
|
|
if (d->buf)
|
|
d->soerrno = -IP_ERRNO_ENOMEM;
|
|
return IP_NULL;
|
|
}
|
|
|
|
if (buf)
|
|
d->buf = (buf + len);
|
|
|
|
return buf;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_push_rtm_hdr
|
|
*===========================================================================
|
|
* Description: Creates a new route message.
|
|
* Parameters: d - dump context.
|
|
* Returns: A pointer to the new route header.
|
|
*
|
|
*/
|
|
IP_STATIC struct Ipnet_rt_msghdr *
|
|
ipnet_sysctl_push_rtm_hdr(Ipnet_sysctl_route_data *d)
|
|
{
|
|
d->rtm = IP_NULL;
|
|
d->rtm = ipnet_sysctl_push_rtm_data(d, sizeof(struct Ipnet_rt_msghdr));
|
|
|
|
if (d->rtm)
|
|
{
|
|
ipcom_memset(d->rtm, 0, sizeof(struct Ipnet_rt_msghdr));
|
|
d->rtm->rtm_msglen = sizeof(struct Ipnet_rt_msghdr);
|
|
}
|
|
|
|
return d->rtm;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_route_dump_fill
|
|
*===========================================================================
|
|
* Description: Fills the route info into the user supplied data area.
|
|
* Parameters: rt - a route entry
|
|
* d - contains, among other things, the area to where
|
|
* the route info should be dumped
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_sysctl_route_dump_fill(Ipnet_route_entry *rt, Ipnet_sysctl_route_data *d)
|
|
{
|
|
struct Ipnet_rt_msghdr *rt_msg;
|
|
void *payload;
|
|
Ip_socklen_t socklen;
|
|
|
|
if ((rt->hdr.flags & d->flags) != d->flags)
|
|
return;
|
|
|
|
/*
|
|
* Do not list the 255.255.255.255, 224.0.0.0/4 or IPv6 multicast
|
|
* routes.
|
|
*/
|
|
if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_X_MCAST_RO | IPNET_RTF_X_BCAST_RO | IPNET_RTF_X_HIDDEN))
|
|
return;
|
|
|
|
/*
|
|
* Add the route header.
|
|
*/
|
|
rt_msg = ipnet_sysctl_push_rtm_hdr(d);
|
|
if (rt_msg)
|
|
{
|
|
rt_msg->rtm_version = IPNET_RTM_VERSION;
|
|
rt_msg->rtm_type = IPNET_RTM_GET;
|
|
rt_msg->rtm_index = rt->netif ? rt->netif->ipcom.ifindex : 0;
|
|
rt_msg->rtm_table = d->table;
|
|
rt_msg->rtm_flags = rt->hdr.flags;
|
|
rt_msg->rtm_use = rt->use;
|
|
rt_msg->rtm_inits = IPNET_RTV_EXPIRE | IPNET_RTV_HOPCOUNT;
|
|
rt_msg->rtm_rmx = rt->metrics;
|
|
}
|
|
|
|
/*
|
|
* Add destination address
|
|
*/
|
|
if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET)
|
|
socklen = sizeof(struct Ip_sockaddr_in);
|
|
else
|
|
socklen = sizeof(struct Ip_sockaddr_in6);
|
|
payload = ipnet_sysctl_push_rtm_data(d, socklen);
|
|
if (payload)
|
|
{
|
|
ipnet_sysctl_fill_route_addr(payload,
|
|
IPNET_ROUTE_GET_FAMILY(rt->head),
|
|
rt->hdr.key);
|
|
if (rt_msg)
|
|
IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_DST);
|
|
}
|
|
|
|
if (rt->gateway)
|
|
{
|
|
payload = ipnet_sysctl_push_rtm_data(d, IPCOM_SA_LEN_GET(rt->gateway));
|
|
if (payload)
|
|
{
|
|
if (rt_msg)
|
|
IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY);
|
|
ipcom_memcpy(payload, rt->gateway, IPCOM_SA_LEN_GET(rt->gateway));
|
|
}
|
|
}
|
|
else if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_CLONING))
|
|
{
|
|
struct Ip_sockaddr_dl *dl;
|
|
|
|
dl = ipnet_sysctl_push_rtm_data(d, sizeof(struct Ip_sockaddr_dl));
|
|
if (dl)
|
|
{
|
|
if (rt_msg)
|
|
IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY);
|
|
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;
|
|
ip_assert(rt->netif != IP_NULL);
|
|
if (rt->netif != IP_NULL)
|
|
{
|
|
dl->sdl_index = (Ip_u16)rt->netif->ipcom.ifindex;
|
|
dl->sdl_type = (Ip_u8)rt->netif->ipcom.type;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rt->hdr.mask)
|
|
{
|
|
/*
|
|
* Add destination mask
|
|
*/
|
|
payload = ipnet_sysctl_push_rtm_data(d, socklen);
|
|
if (payload)
|
|
{
|
|
if (rt_msg)
|
|
IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_NETMASK);
|
|
ipnet_sysctl_fill_route_addr(payload,
|
|
IPNET_ROUTE_GET_FAMILY(rt->head),
|
|
rt->hdr.mask);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_route_dump_different_gw
|
|
*===========================================================================
|
|
* Description: Dumps all routes with a specific key and mask but
|
|
* different gateway.
|
|
* Parameters: rt_arg - a route entry
|
|
* data - data area to dump routes to
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_sysctl_route_dump_different_gw(Ipnet_route_entry *rt_arg, Ipnet_sysctl_route_data *data)
|
|
{
|
|
Ipnet_route_entry *rt;
|
|
|
|
for (rt = rt_arg; rt != IP_NULL; rt = rt->next)
|
|
ipnet_sysctl_route_dump_fill(rt, data);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_route_dump_cb
|
|
*===========================================================================
|
|
* Description: Dumps all routes with a specific search key.
|
|
* Parameters: rt_arg - the route entry to dump
|
|
* data - callback data.
|
|
* Returns: IP_FALSE (the entry should never be deleted).
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipnet_sysctl_route_dump_cb(Ipnet_route_entry *rt_arg, Ipnet_sysctl_route_data *data)
|
|
{
|
|
Ipnet_route_entry *rt;
|
|
|
|
for (rt = rt_arg; rt != IP_NULL; rt = rt->narrow)
|
|
ipnet_sysctl_route_dump_different_gw(rt, data);
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_for_each_rtab_cb
|
|
*===========================================================================
|
|
* Description: Dumps all routes entries for every route table.
|
|
* Parameters: rtab - The route table to dump.
|
|
* d - The route dump parameters.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_sysctl_for_each_rtab_cb(Ipcom_route *rtab, Ipnet_sysctl_route_data *d)
|
|
{
|
|
if (d->vr != IPNET_ROUTE_GET_VR(rtab))
|
|
return;
|
|
if (d->domain != 0 && d->domain != IPNET_ROUTE_GET_FAMILY(rtab))
|
|
return;
|
|
|
|
d->table = IPNET_ROUTE_GET_TABLE(rtab);
|
|
ipcom_route_walk_tree(rtab,
|
|
(Ipcom_route_walk_cb) ipnet_sysctl_route_dump_cb,
|
|
d);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_foreach_neigh_cb
|
|
*===========================================================================
|
|
* Description: Dumps all the neighbors to BSD route messages.
|
|
* Parameters: neigh - a neighbor entry
|
|
* d - storage area for the dump
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_sysctl_foreach_neigh_cb(Ipnet_neigh *neigh, Ipnet_sysctl_route_data *d)
|
|
{
|
|
struct Ipnet_rt_msghdr *rt_msg;
|
|
struct Ip_sockaddr_dl *dl;
|
|
Ipnet_netif *netif = neigh->netif;
|
|
union Ip_sockaddr_union *dst;
|
|
|
|
if (d->vr != netif->vr_index
|
|
|| (d->domain != 0 && d->domain != neigh->key_domain))
|
|
return;
|
|
|
|
/*
|
|
* Add the route header.
|
|
*/
|
|
rt_msg = ipnet_sysctl_push_rtm_hdr(d);
|
|
if (rt_msg != IP_NULL)
|
|
{
|
|
rt_msg->rtm_version = IPNET_RTM_VERSION;
|
|
rt_msg->rtm_type = IPNET_RTM_GET;
|
|
rt_msg->rtm_index = netif->ipcom.ifindex;
|
|
rt_msg->rtm_table = d->table;
|
|
rt_msg->rtm_addrs = (IPNET_RTA_DST | IPNET_RTA_GATEWAY);
|
|
rt_msg->rtm_inits = IPNET_RTV_EXPIRE | IPNET_RTV_HOPCOUNT;
|
|
rt_msg->rtm_rmx.rmx_hopcount = 1;
|
|
if (neigh->tmo)
|
|
rt_msg->rtm_rmx.rmx_expire = (Ip_u32) (ipnet_timeout_msec_until(neigh->tmo) / 1000);
|
|
else
|
|
rt_msg->rtm_rmx.rmx_expire = IPCOM_ADDR_INFINITE;
|
|
|
|
/*
|
|
* Translate neighbor flags to BSD route flags
|
|
*/
|
|
rt_msg->rtm_flags = (IPNET_RTF_UP
|
|
| IPNET_RTF_HOST
|
|
| IPNET_RTF_LLINFO);
|
|
if (ipnet_neigh_is_publ(neigh))
|
|
IP_BIT_SET(rt_msg->rtm_flags, IPNET_RTF_PROTO2);
|
|
if (ipnet_neigh_has_local(neigh))
|
|
IP_BIT_SET(rt_msg->rtm_flags, IPNET_RTF_LOCAL);
|
|
if (ipnet_neigh_is_blackhole(neigh))
|
|
IP_BIT_SET(rt_msg->rtm_flags, IPNET_RTF_BLACKHOLE);
|
|
if (ipnet_neigh_is_complete(neigh))
|
|
IP_BIT_SET(rt_msg->rtm_flags, IPNET_RTF_DONE);
|
|
}
|
|
|
|
/*
|
|
* Add IP address
|
|
*/
|
|
switch (neigh->domain)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
dst = ipnet_sysctl_push_rtm_data(d, sizeof(struct Ip_sockaddr_in));
|
|
if (dst)
|
|
{
|
|
ipcom_memset(dst, 0, sizeof(struct Ip_sockaddr_in));
|
|
IPCOM_SA_LEN_SET(&dst->sin, sizeof(struct Ip_sockaddr_in));
|
|
dst->sin.sin_family = IP_AF_INET;
|
|
dst->sin.sin_addr = neigh->addr.in;
|
|
}
|
|
break;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
dst = ipnet_sysctl_push_rtm_data(d, sizeof(struct Ip_sockaddr_in6));
|
|
if (dst)
|
|
{
|
|
ipcom_memset(dst, 0, sizeof(struct Ip_sockaddr_in6));
|
|
IPCOM_SA_LEN_SET(&dst->sin6, sizeof(struct Ip_sockaddr_in6));
|
|
dst->sin6.sin6_family = IP_AF_INET6;
|
|
dst->sin6.sin6_addr = neigh->addr.in6;
|
|
}
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Add link layer address
|
|
*/
|
|
dl = ipnet_sysctl_push_rtm_data(d, sizeof(*dl));
|
|
if (dl != IP_NULL)
|
|
{
|
|
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_nlen = (Ip_u8) 0;
|
|
dl->sdl_alen = (Ip_u8) netif->ipcom.link_addr_size;
|
|
dl->sdl_type = (Ip_u8) netif->ipcom.type;
|
|
memcpy(IP_SOCKADDR_DL_LLADDR(dl),
|
|
neigh->lladdr,
|
|
netif->ipcom.link_addr_size);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_route_dump
|
|
*===========================================================================
|
|
* Description: Dumps all routes entries.
|
|
* Parameters: oldp - buffer to where the route entries will be copied
|
|
* oldlenp - [in] the length of 'oldp' buffer
|
|
* [out] the number of bytes copied to 'oldp' buffer or
|
|
* the number of bytes needed (if 'oldp' is IP_NULL).
|
|
* domain - the domain to return routes for (0=all domains)
|
|
* flags - the IPNET_RTF_xxx flags that must be set in the returned
|
|
* entries.
|
|
* Returns: 0 == success, <0 == error code.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_sysctl_route_dump(Ip_u16 vr, void *oldp, Ip_size_t *oldlenp, int domain, Ip_u32 flags)
|
|
{
|
|
Ipnet_sysctl_route_data data;
|
|
|
|
data.buf = oldp;
|
|
if (oldp == IP_NULL)
|
|
data.buf_len = 0;
|
|
else
|
|
data.buf_len = *oldlenp;
|
|
data.bytes_written = 0;
|
|
data.flags = flags;
|
|
data.soerrno = 0;
|
|
data.domain = domain;
|
|
data.vr = vr;
|
|
|
|
if (flags == IPNET_RTF_LLINFO)
|
|
/*
|
|
* It this a good workaround?
|
|
*/
|
|
ipnet_neigh_foreach((Ipnet_neigh_foreach_func)ipnet_sysctl_foreach_neigh_cb,
|
|
&data);
|
|
else
|
|
/*
|
|
* Dump
|
|
*/
|
|
if (ipnet->rtabs != IP_NULL)
|
|
ipcom_hash_for_each(ipnet->rtabs,
|
|
(Ipcom_hash_foreach_cb_func) ipnet_sysctl_for_each_rtab_cb,
|
|
&data);
|
|
|
|
if (oldlenp)
|
|
*oldlenp = data.bytes_written;
|
|
return data.soerrno;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_if_add_ip4_addr
|
|
*===========================================================================
|
|
* Description: Adds a IPv4 socket address to the buffer.
|
|
* Parameters: buf - the buffer where the socket address should be written.
|
|
* addr_n - the address in network byte order.
|
|
* Returns: Pointer to where next address should be written.
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET
|
|
IP_STATIC void *
|
|
ipnet_sysctl_if_add_ip4_addr(void *buf, Ip_u32 addr_n)
|
|
{
|
|
struct Ip_sockaddr_in *in = (struct Ip_sockaddr_in *) buf;
|
|
|
|
ipcom_memset(in, 0, sizeof(struct Ip_sockaddr_in));
|
|
in->sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(in, sizeof(struct Ip_sockaddr_in));
|
|
ipcom_memcpy(&in->sin_addr, &addr_n, sizeof(in->sin_addr));
|
|
|
|
return in + 1;
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_if_add_ip6_addr
|
|
*===========================================================================
|
|
* Description: Adds a IPv6 socket address to the buffer.
|
|
* Parameters: buf - the buffer where the socket address should be written.
|
|
* addr - the address in network byte order.
|
|
* is_scoped - IP_TRUE if the address or mask is scoped.
|
|
* scope_id - The scope_id to use if the mask/address is scoped.
|
|
* Returns: Pointer to where next address should be written.
|
|
*
|
|
*/
|
|
IP_STATIC void *
|
|
ipnet_sysctl_if_add_ip6_addr(void *buf,
|
|
IP_CONST struct Ip_in6_addr *addr,
|
|
Ip_bool is_scoped,
|
|
Ip_u32 scope_id)
|
|
{
|
|
struct Ip_sockaddr_in6 *in6 = (struct Ip_sockaddr_in6 *) buf;
|
|
|
|
ipcom_memset(in6, 0, sizeof(struct Ip_sockaddr_in6));
|
|
in6->sin6_family = IP_AF_INET6;
|
|
IPCOM_SA_LEN_SET(in6, sizeof(struct Ip_sockaddr_in6));
|
|
in6->sin6_scope_id = (is_scoped ? scope_id : 0);
|
|
IPNET_IP6_SET_ADDR(&in6->sin6_addr, addr);
|
|
|
|
return in6 + 1;
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_if_add_addrs
|
|
*===========================================================================
|
|
* Description: Adds a Ipnet_ifa_msghdr structure for each address matching
|
|
* the domain assigned to the specified interface.
|
|
* Parameters: buf - buffer to where the addresses will be copied.
|
|
* netif - interface for which all addresses should be added.
|
|
* domain - the domain to return addresses for (0=all domains)
|
|
* Returns: Number of bytes added or bytes needed if buf == IP_NULL
|
|
*
|
|
*/
|
|
IP_STATIC Ip_size_t
|
|
ipnet_sysctl_if_add_addrs(void *buf, Ipnet_netif *netif, int domain)
|
|
{
|
|
Ip_size_t len = 0;
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (domain == 0 || domain == IP_AF_INET)
|
|
{
|
|
Ipnet_ip4_addr_entry *addr4;
|
|
|
|
addr4 = netif->inet4_addr_list;
|
|
if (IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_POINTOPOINT) && addr4 == IP_NULL)
|
|
(void)ipnet_sysctl_if_add_addrs_one(buf, netif, IP_AF_INET, IP_NULL, &len);
|
|
else
|
|
for (; addr4 != IP_NULL; addr4 = addr4->next)
|
|
{
|
|
#if defined (IPNGC) || defined (IPQUAGGA)
|
|
/*!! show them or not? */
|
|
if (addr4->type == IPNET_ADDR_TYPE_MULTICAST)
|
|
continue;
|
|
#endif
|
|
if (addr4->type == IPNET_ADDR_TYPE_NETBROADCAST)
|
|
continue;
|
|
|
|
#if defined(IPNET_USE_RFC5227) || defined(IPNET_USE_RFC3927)
|
|
/* Don't show tentative addresses */
|
|
if (IP_BIT_ISSET(addr4->flags, IPNET_IP4_ADDR_FLAG_TENTATIVE))
|
|
continue;
|
|
#endif
|
|
|
|
buf = ipnet_sysctl_if_add_addrs_one(buf, netif, IP_AF_INET, addr4, &len);
|
|
}
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (domain == 0 || domain == IP_AF_INET6)
|
|
{
|
|
Ipnet_ip6_addr_entry *addr6;
|
|
|
|
for (addr6 = netif->inet6_addr_list; addr6 != IP_NULL; addr6 = addr6->next)
|
|
{
|
|
#if defined (IPNGC) || defined (IPQUAGGA)
|
|
/*!! show them or not? */
|
|
if (addr6->type == IPNET_ADDR_TYPE_MULTICAST)
|
|
continue;
|
|
#endif
|
|
buf = ipnet_sysctl_if_add_addrs_one(buf, netif, IP_AF_INET6, addr6, &len);
|
|
}
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_if_dump
|
|
*===========================================================================
|
|
* Description: Dumps interface entries.
|
|
* Parameters: oldp - buffer to where the interface entries will be copied
|
|
* oldlenp - [in] the length of 'oldp' buffer
|
|
* [out] the number of bytes copied to 'oldp' buffer or
|
|
* the number of bytes needed (if 'oldp' is IP_NULL).
|
|
* domain - the domain to return addresses for (0=all domains)
|
|
* ifindex - the interface to return informtaion for (0=interfaces)
|
|
* Returns: 0 == success, <0 == error code.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_sysctl_if_dump(Ip_u16 vr, void *oldp, Ip_size_t *oldlenp, int domain, Ip_u32 ifindex)
|
|
{
|
|
Ip_size_t total_bytes = 0;
|
|
Ip_size_t written = 0;
|
|
Ipnet_netif *netif;
|
|
Ip_u32 *ifindexes = IP_NULL;
|
|
int ret = 0;
|
|
unsigned num_elem;
|
|
Ip_u32 i;
|
|
|
|
|
|
/*
|
|
* IPNET_NETIF_FOR_EACH_OR_SPECIFIC_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_OR_SPECIFIC_ON_VR(netif, vr, ifindex, i)
|
|
{
|
|
total_bytes += ipnet_sysctl_create_ifinfo(IP_NULL, netif);
|
|
total_bytes += ipnet_sysctl_if_add_addrs(IP_NULL, netif, domain);
|
|
}
|
|
|
|
if (total_bytes == 0)
|
|
{
|
|
/* Invalid ifindex */
|
|
ret = -IP_ERRNO_ENXIO;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (oldp == IP_NULL)
|
|
{
|
|
*oldlenp = total_bytes;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (total_bytes > *oldlenp)
|
|
{
|
|
ret = -IP_ERRNO_ENOMEM;
|
|
goto cleanup;
|
|
}
|
|
|
|
ifindexes = ipnet_if_get_index_array(vr, ifindex, &num_elem);
|
|
if (ifindexes == IP_NULL)
|
|
return -IP_ERRNO_ENOMEM;
|
|
|
|
for (i = 0; i < num_elem; i++)
|
|
{
|
|
netif = ipnet_if_indextonetif(vr, ifindexes[i]);
|
|
written += ipnet_sysctl_create_ifinfo((Ip_u8 *) oldp + written, netif);
|
|
written += ipnet_sysctl_if_add_addrs((Ip_u8 *) oldp + written, netif, domain);
|
|
}
|
|
|
|
ip_assert(written == total_bytes);
|
|
*oldlenp = written;
|
|
|
|
cleanup:
|
|
ipcom_free(ifindexes);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_inet4
|
|
*===========================================================================
|
|
* Description: System control for IPv4.
|
|
* Parameters: name - the hierarchical sysctl name.
|
|
* namelen - the size of the 'name' array.
|
|
* oldp - buffer to where the route entries will be copied
|
|
* oldlen - [in] the length of 'oldp' buffer
|
|
* [out] the number of bytes copied to 'oldp' buffer or
|
|
* the number of bytes needed (if 'oldp' is IP_NULL).
|
|
* newp - the new value for the variable
|
|
* newlen - the length of the 'newp' buffer.
|
|
* Returns: 0 == success, <0 == error code.
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET
|
|
IP_STATIC int
|
|
ipnet_sysctl_inet4(Ip_u16 vr,
|
|
int *name, unsigned int namelen,
|
|
void *oldp, Ip_size_t *oldlen,
|
|
void *newp, Ip_size_t newlen)
|
|
{
|
|
if (namelen < 4)
|
|
return -IP_ERRNO_ENOTDIR;
|
|
|
|
switch (name[2])
|
|
{
|
|
case IP_IPPROTO_IP:
|
|
/* Size check */
|
|
switch (name[3])
|
|
{
|
|
case IP_IPCTL_FORWARDING:
|
|
#ifdef IP_IPCTL_SENDREDIRECTS
|
|
case IP_IPCTL_SENDREDIRECTS:
|
|
#endif
|
|
#ifdef IP_IPCTL_MTUDISC
|
|
case IP_IPCTL_MTUDISC:
|
|
#endif
|
|
if (oldp && *oldlen < sizeof(int))
|
|
return -IP_ERRNO_ENOMEM;
|
|
if (newp && newlen != sizeof(int))
|
|
return -IP_ERRNO_EINVAL;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Action */
|
|
switch (name[3])
|
|
{
|
|
case IP_IPCTL_FORWARDING:
|
|
if (namelen > 4)
|
|
{
|
|
Ipnet_netif *netif = ipnet_if_indextonetif(vr, name[4]);
|
|
if (netif == IP_NULL)
|
|
return -IP_ERRNO_ENXIO;
|
|
|
|
|
|
if (oldp)
|
|
{
|
|
*((int *) oldp) = IP_BIT_ISFALSE(netif->flags2, IPNET_IFF2_NO_IPV4_FORWARD);
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
if (*(int*) newp)
|
|
IP_BIT_CLR(netif->flags2, IPNET_IFF2_NO_IPV4_FORWARD);
|
|
else
|
|
IP_BIT_SET(netif->flags2, IPNET_IFF2_NO_IPV4_FORWARD);
|
|
|
|
#ifdef IPNET_USE_RFC1256
|
|
ipnet_ip4_rfc1256_mode_update(netif->vr_index, netif);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (oldp)
|
|
{
|
|
*((int *) oldp) = (IP_BIT_ISSET(ipnet_flags, IPNET_FLAG_IPV4_FORWARD_PKT) ? 1 : 0);
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
if (*(int*) newp)
|
|
IP_BIT_SET(ipnet_flags, IPNET_FLAG_IPV4_FORWARD_PKT);
|
|
else
|
|
IP_BIT_CLR(ipnet_flags, IPNET_FLAG_IPV4_FORWARD_PKT);
|
|
|
|
#ifdef IPNET_USE_RFC1256
|
|
ipnet_ip4_rfc1256_mode_update(vr, IP_NULL);
|
|
#endif
|
|
}
|
|
}
|
|
ipnet_dst_cache_flush(IPCOM_VR_ANY, 0);
|
|
break;
|
|
|
|
#ifdef IP_IPCTL_SENDREDIRECTS
|
|
case IP_IPCTL_SENDREDIRECTS:
|
|
if (oldp)
|
|
{
|
|
int val = ipcom_sysvar_get_as_int_vr("ipnet.inet.IcmpRedirectSend", 2, vr);
|
|
*((int *) oldp) = val > 0 ? 1 : 0;
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
#if IPCOM_VR_MAX > 1
|
|
int old_vr = ipcom_proc_vr_get();
|
|
/* When non tNet task called ipnet sysctl, after task swich the env must
|
|
be set in tNet0 task context and restore it after calling ipcom sysvar API. */
|
|
(void)ipcom_proc_vr_set(vr);
|
|
#endif
|
|
if (*(int*) newp)
|
|
/* 2 if a redirect should be sent and the original message should be forwarded */
|
|
(void)ipcom_sysvar_setvr("ipnet.inet.IcmpRedirectSend", "2", IPCOM_SYSVAR_FLAG_OVERWRITE, vr);
|
|
else
|
|
/* 0 if no redirect should be sent but the original message should be forwarded */
|
|
(void)ipcom_sysvar_setvr("ipnet.inet.IcmpRedirectSend", "0", IPCOM_SYSVAR_FLAG_OVERWRITE, vr);
|
|
#if IPCOM_VR_MAX > 1
|
|
(void)ipcom_proc_vr_set(old_vr);
|
|
#endif
|
|
}
|
|
break;
|
|
#endif /* IP_IPCTL_SENDREDIRECTS */
|
|
|
|
#ifdef IP_IPCTL_MTUDISC
|
|
case IP_IPCTL_MTUDISC:
|
|
if (oldp)
|
|
{
|
|
int val = ipcom_sysvar_get_as_int_vr("ipnet.inet.EnablePathMtuDiscovery", 1, vr);
|
|
*((int *) oldp) = val > 0 ? 1 : 0;
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
#if IPCOM_VR_MAX > 1
|
|
int old_vr = ipcom_proc_vr_get();
|
|
/* When non tNet task called ipnet sysctl, after task swich the env must
|
|
be set in tNet0 task context and restore it after calling ipcom sysvar API. */
|
|
(void)ipcom_proc_vr_set(vr);
|
|
#endif
|
|
(void)ipcom_sysvar_setvr("ipnet.inet.EnablePathMtuDiscovery",
|
|
*(int*) newp ? "1" : "0",
|
|
IPCOM_SYSVAR_FLAG_OVERWRITE, vr);
|
|
#if IPCOM_VR_MAX > 1
|
|
(void)ipcom_proc_vr_set(old_vr);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
#endif /* IP_IPCTL_MTUDISC */
|
|
|
|
case IP_IPCTL_STRICT_MODE:
|
|
if (oldp)
|
|
{
|
|
*((int *) oldp) = (IP_BIT_ISSET(ipnet_flags, IPNET_FLAG_IPV4_STRICT_MODE) ? 1 : 0);
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
if (*(int*) newp)
|
|
IP_BIT_SET(ipnet_flags, IPNET_FLAG_IPV4_STRICT_MODE);
|
|
else
|
|
IP_BIT_CLR(ipnet_flags, IPNET_FLAG_IPV4_STRICT_MODE);
|
|
ipnet_dst_cache_flush(vr, IP_AF_INET);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case IP_IPPROTO_UDP:
|
|
switch (name[3])
|
|
{
|
|
#ifdef IP_UDPCTL_CHECKSUM
|
|
case IP_UDPCTL_CHECKSUM:
|
|
if (oldp && *oldlen < sizeof(int))
|
|
return -IP_ERRNO_ENOMEM;
|
|
if (newp && newlen != sizeof(int))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
if (oldp)
|
|
{
|
|
*((int *) oldp) = ipnet->conf.inet.udp_checksum;
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
#if IPCOM_VR_MAX > 1
|
|
int old_vr = ipcom_proc_vr_get();
|
|
/* When non tNet task called ipnet sysctl, after task swich the env must
|
|
be set in tNet0 task context and restore it after calling ipcom sysvar API. */
|
|
(void)ipcom_proc_vr_set(vr);
|
|
#endif
|
|
(void)ipcom_sysvar_setvr("ipnet.inet.UdpChecksum",
|
|
*(int*) newp ? "1" : "0",
|
|
IPCOM_SYSVAR_FLAG_OVERWRITE, vr);
|
|
#if IPCOM_VR_MAX > 1
|
|
(void)ipcom_proc_vr_set(old_vr);
|
|
#endif
|
|
}
|
|
return 0;
|
|
#endif /* IP_UDPCTL_CHECKSUM */
|
|
default:
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_ip6
|
|
*===========================================================================
|
|
* Description: System control for IPv4.
|
|
* Parameters: name - the hierarchical sysctl name.
|
|
* namelen - the size of the 'name' array.
|
|
* oldp - buffer to where the route entries will be copied
|
|
* oldlen - [in] the length of 'oldp' buffer
|
|
* [out] the number of bytes copied to 'oldp' buffer or
|
|
* the number of bytes needed (if 'oldp' is IP_NULL).
|
|
* newp - the new value for the variable
|
|
* newlen - the length of the 'newp' buffer.
|
|
* Returns: 0 == success, <0 == error code.
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET6
|
|
#include <ipcom_syslog.h>
|
|
IP_STATIC int
|
|
ipnet_sysctl_inet6(Ip_u16 vr,
|
|
int *name, unsigned int namelen,
|
|
void *oldp, Ip_size_t *oldlen,
|
|
void *newp, Ip_size_t newlen)
|
|
{
|
|
Ipnet_netif *netif = IP_NULL;
|
|
int name_tmp[5];
|
|
|
|
if (namelen < 4)
|
|
return -IP_ERRNO_ENOTDIR;
|
|
|
|
if (name[2] != IP_IPPROTO_IPV6)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
switch (name[3])
|
|
{
|
|
case IP_IPV6CTL_ACCEPT_RTADV:
|
|
case IP_IPV6CTL_ENABLED:
|
|
case IP_IPV6CTL_ND_CURHOPLIMIT:
|
|
/* Set all the interfaces */
|
|
if (namelen == 4)
|
|
{
|
|
Ip_u32 i;
|
|
int ret;
|
|
|
|
ipcom_memcpy(name_tmp, name, namelen * sizeof(int));
|
|
/* For all the interfaces on this vr */
|
|
/*
|
|
* 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, vr, i)
|
|
{
|
|
name_tmp[4] = netif->ipcom.ifindex;
|
|
namelen = 5;
|
|
ret = ipnet_sysctl_inet6(vr, name_tmp, namelen, oldp, oldlen, newp, newlen);
|
|
if (ret != 0)
|
|
{
|
|
IPCOM_LOG1(ERR,"interface %s sysctl set error\n",netif->ipcom.name);
|
|
return ret;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
netif = ipnet_if_indextonetif(vr, name[4]);
|
|
if (netif == IP_NULL)
|
|
return -IP_ERRNO_ENXIO;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (name[3])
|
|
{
|
|
case IP_IPV6CTL_FORWARDING:
|
|
if (namelen > 4)
|
|
{
|
|
netif = ipnet_if_indextonetif(vr, name[4]);
|
|
if (netif == IP_NULL)
|
|
return -IP_ERRNO_ENXIO;
|
|
|
|
if (oldp)
|
|
{
|
|
if (*oldlen < sizeof(int))
|
|
return -IP_ERRNO_ENOMEM;
|
|
*((int *) oldp) = IP_BIT_ISFALSE(netif->flags2, IPNET_IFF2_NO_IPV6_FORWARD);
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
if (newlen != sizeof(int))
|
|
return -IP_ERRNO_EINVAL;
|
|
if (*(int*) newp)
|
|
IP_BIT_CLR(netif->flags2, IPNET_IFF2_NO_IPV6_FORWARD);
|
|
else
|
|
IP_BIT_SET(netif->flags2, IPNET_IFF2_NO_IPV6_FORWARD);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (oldp)
|
|
{
|
|
if (*oldlen < sizeof(int))
|
|
return -IP_ERRNO_ENOMEM;
|
|
*((int *) oldp) = (IP_BIT_ISSET(ipnet_flags, IPNET_FLAG_IPV6_FORWARD_PKT) ? 1 : 0);
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
if (newlen != sizeof(int))
|
|
return -IP_ERRNO_EINVAL;
|
|
if (*(int*) newp)
|
|
IP_BIT_SET(ipnet_flags, IPNET_FLAG_IPV6_FORWARD_PKT);
|
|
else
|
|
IP_BIT_CLR(ipnet_flags, IPNET_FLAG_IPV6_FORWARD_PKT);
|
|
}
|
|
}
|
|
ipnet_dst_cache_flush(IPCOM_VR_ANY, 0);
|
|
break;
|
|
|
|
case IP_IPV6CTL_ACCEPT_RTADV:
|
|
if (oldp)
|
|
{
|
|
if (*oldlen < sizeof(int))
|
|
return -IP_ERRNO_ENOMEM;
|
|
*((int *) oldp) = netif->conf.inet6.accept_rt_adv;
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
char sysname[IP_IFNAMSIZ + 1 + 20];
|
|
#if IPCOM_VR_MAX > 1
|
|
int old_vr = ipcom_proc_vr_get();
|
|
/* When non tNet task called ipnet sysctl, after task swich the env must
|
|
be set in tNet0 task context and restore it after calling ipcom sysvar API. */
|
|
(void)ipcom_proc_vr_set(vr);
|
|
#endif
|
|
|
|
if (newlen != sizeof(int))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
ipcom_snprintf(sysname, sizeof(sysname), "%s.inet6.AcceptRtAdv", netif->ipcom.name);
|
|
if (*(int*) newp)
|
|
(void)ipcom_sysvar_setvr(sysname, "yes", IPCOM_SYSVAR_FLAG_OVERWRITE, vr);
|
|
else
|
|
(void)ipcom_sysvar_setvr(sysname, "no", IPCOM_SYSVAR_FLAG_OVERWRITE, vr);
|
|
#if IPCOM_VR_MAX > 1
|
|
(void)ipcom_proc_vr_set(old_vr);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case IP_IPV6CTL_ENABLED:
|
|
if (oldp)
|
|
{
|
|
if (*oldlen < sizeof(int))
|
|
return -IP_ERRNO_ENOMEM;
|
|
*((int *) oldp) = IP_BIT_ISFALSE(netif->flags2, IPNET_IFF2_IPV6_DISABLED);
|
|
*oldlen = sizeof(int);
|
|
}
|
|
if (newp)
|
|
{
|
|
if (newlen != sizeof(int))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
if (*(int*) newp)
|
|
{
|
|
IP_BIT_CLR(netif->flags2, IPNET_IFF2_IPV6_DISABLED);
|
|
ipnet_ip6_kioevent(netif, IP_EIOXUP);
|
|
}
|
|
else
|
|
{
|
|
IP_BIT_SET(netif->flags2, IPNET_IFF2_IPV6_DISABLED);
|
|
ipnet_ip6_kioevent(netif, IP_EIOXDOWN);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IP_IPV6CTL_ND_CURHOPLIMIT:
|
|
if (oldp)
|
|
{
|
|
if (*oldlen < sizeof(int))
|
|
return -IP_ERRNO_ENOMEM;
|
|
*((int *) oldp) = netif->inet6_nd_curhoplimit;
|
|
*oldlen = sizeof(int);
|
|
}
|
|
if (newp)
|
|
{
|
|
int newval;
|
|
|
|
if (newlen != sizeof(int))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
newval = *(int*) newp;
|
|
if (newval < 0 || newval > 255)
|
|
return -IP_ERRNO_ERANGE;
|
|
netif->inet6_nd_curhoplimit = (Ip_u8) newval;
|
|
}
|
|
break;
|
|
|
|
case IP_IPV6CTL_STRICT_MODE:
|
|
if (oldp)
|
|
{
|
|
*((int *) oldp) = (IP_BIT_ISSET(ipnet_flags, IPNET_FLAG_IPV6_STRICT_MODE) ? 1 : 0);
|
|
*oldlen = sizeof(int);
|
|
}
|
|
|
|
if (newp)
|
|
{
|
|
if (*(int*) newp)
|
|
IP_BIT_SET(ipnet_flags, IPNET_FLAG_IPV6_STRICT_MODE);
|
|
else
|
|
IP_BIT_CLR(ipnet_flags, IPNET_FLAG_IPV6_STRICT_MODE);
|
|
ipnet_dst_cache_flush(vr, IP_AF_INET6);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_route
|
|
*===========================================================================
|
|
* Description: System control for IPNET_AF_INET domain.
|
|
* Parameters: name - the hierarchical sysctl name.
|
|
* namelen - the size of the 'name' array.
|
|
* oldp - buffer to where the route entries will be copied
|
|
* oldlenp - [in] the length of 'oldp' buffer
|
|
* [out] the number of bytes copied to 'oldp' buffer or
|
|
* the number of bytes needed (if 'oldp' is IP_NULL).
|
|
* Returns: 0 == success, <0 == error code.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_sysctl_route(Ip_u16 vr, int *name, unsigned int namelen, void *oldp, Ip_size_t *oldlenp)
|
|
{
|
|
if (namelen < 6)
|
|
return -IP_ERRNO_ENOTDIR;
|
|
|
|
if (name[2] != 0)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
switch (name[4])
|
|
{
|
|
case IP_NET_RT_DUMP:
|
|
case IP_NET_RT_FLAGS:
|
|
return ipnet_sysctl_route_dump(vr, oldp, oldlenp, name[3], name[5]);
|
|
case IP_NET_RT_IFLIST:
|
|
return ipnet_sysctl_if_dump(vr, oldp, oldlenp, name[3], name[5]);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return -IP_ERRNO_ENOTDIR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_net
|
|
*===========================================================================
|
|
* Description: System control for IPNET_CTL_NET.
|
|
* Parameters: name - the hierarchical sysctl name.
|
|
* namelen - the size of the 'name' array.
|
|
* oldp - buffer to where the route entries will be copied
|
|
* oldlen - [in] the length of 'oldp' buffer
|
|
* [out] the number of bytes copied to 'oldp' buffer or
|
|
* the number of bytes needed (if 'oldp' is IP_NULL).
|
|
* newp - the new value for the variable
|
|
* newlen - the length of the 'newp' buffer.
|
|
* Returns: 0 == success, <0 == error code.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_sysctl_net(Ip_u16 vr,
|
|
int *name, unsigned int namelen,
|
|
void *oldp, Ip_size_t *oldlen,
|
|
void *newp, Ip_size_t newlen)
|
|
{
|
|
switch (name[1])
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET :
|
|
return ipnet_sysctl_inet4(vr, name, namelen, oldp, oldlen, newp, newlen);
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6 :
|
|
return ipnet_sysctl_inet6(vr, name, namelen, oldp, oldlen, newp, newlen);
|
|
#endif
|
|
case IP_AF_ROUTE :
|
|
if (newp != IP_NULL)
|
|
/* All route values are read-only */
|
|
return -IP_ERRNO_EPERM;
|
|
return ipnet_sysctl_route(vr, name, namelen, oldp, oldlen);
|
|
default:
|
|
return -IP_ERRNO_ENOTDIR;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_if_add_addrs_one
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void *
|
|
ipnet_sysctl_if_add_addrs_one(void *buf, Ipnet_netif *netif, int domain, void *addrx, Ip_size_t *lenp)
|
|
{
|
|
Ip_size_t elem_len;
|
|
Ip_size_t dl_len;
|
|
struct Ipnet_ifa_msghdr *ifa = IP_NULL;
|
|
|
|
elem_len = sizeof(struct Ipnet_ifa_msghdr);
|
|
if (buf != IP_NULL)
|
|
{
|
|
ifa = (struct Ipnet_ifa_msghdr *) buf;
|
|
ifa->ifam_version = IPNET_RTM_VERSION;
|
|
ifa->ifam_type = IPNET_RTM_NEWADDR;
|
|
ifa->ifam_addrs = IPNET_RTA_NETMASK | IPNET_RTA_IFA | IPNET_RTA_IFP;
|
|
ifa->ifam_flags = IPNET_RTF_UP;
|
|
if (IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_NOARP | IP_IFF_POINTOPOINT | IP_IFF_LOOPBACK))
|
|
IP_BIT_SET(ifa->ifam_flags, IPNET_RTF_CLONING);
|
|
ifa->ifam_index = netif->ipcom.ifindex;
|
|
ifa->ifam_metric = netif->ipcom.metric;
|
|
buf = ifa + 1;
|
|
}
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (domain == IP_AF_INET)
|
|
{
|
|
Ipnet_ip4_addr_entry *addr4 = (Ipnet_ip4_addr_entry *)addrx;
|
|
|
|
/* It is now the _third_ time I add the "addr4 &&" check. do NOT remove or crash on OSE5! */
|
|
if (addr4 && IP_IN_CLASSD(addr4->ipaddr_n) && ifa != IP_NULL)
|
|
IP_BIT_CLR(ifa->ifam_flags, IPNET_RTF_CLONING);
|
|
|
|
if (addr4 == IP_NULL
|
|
|| (IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_POINTOPOINT)
|
|
&& IP_IN_CLASSD(addr4->ipaddr_n) == IP_FALSE))
|
|
{
|
|
struct Ip_ifreq ifreq;
|
|
struct Ip_sockaddr_in *inaddr = (struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr;
|
|
|
|
/* IPNET_RTA_NETMASK */
|
|
elem_len += sizeof(struct Ip_sockaddr_in);
|
|
if (buf != IP_NULL)
|
|
{
|
|
if (addr4 != IP_NULL)
|
|
buf = ipnet_sysctl_if_add_ip4_addr(buf, addr4->netmask_n);
|
|
else
|
|
buf = ipnet_sysctl_if_add_ip4_addr(buf, 0xffffffff);
|
|
}
|
|
/* IPNET_RTA_IFP */
|
|
dl_len = ipnet_if_to_sockaddr_dl(netif, buf);
|
|
elem_len += dl_len;
|
|
if (buf != IP_NULL)
|
|
buf = (Ip_u8 *)buf + dl_len;
|
|
/* IPNET_RTA_IFA */
|
|
elem_len += sizeof(struct Ip_sockaddr_in);
|
|
if (buf != IP_NULL)
|
|
{
|
|
if (addr4 != IP_NULL)
|
|
buf = ipnet_sysctl_if_add_ip4_addr(buf, addr4->ipaddr_n);
|
|
else
|
|
{
|
|
(void) ipnet_if_link_ioctl(netif, IP_SIOCGIFADDR, &ifreq);
|
|
buf = ipnet_sysctl_if_add_ip4_addr(buf, inaddr->sin_addr.s_addr);
|
|
}
|
|
}
|
|
/* IPNET_RTA_BRD */
|
|
elem_len += sizeof(struct Ip_sockaddr_in);
|
|
if (buf != IP_NULL)
|
|
{
|
|
IP_BIT_SET(ifa->ifam_addrs, IPNET_RTA_BRD);
|
|
(void) ipnet_if_link_ioctl(netif, IP_SIOCGIFDSTADDR, &ifreq);
|
|
buf = ipnet_sysctl_if_add_ip4_addr(buf, inaddr->sin_addr.s_addr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ip_assert(addr4);
|
|
/* IPNET_RTA_NETMASK */
|
|
elem_len += sizeof(struct Ip_sockaddr_in);
|
|
if (buf != IP_NULL)
|
|
buf = ipnet_sysctl_if_add_ip4_addr(buf, addr4->netmask_n);
|
|
/* IPNET_RTA_IFP */
|
|
dl_len = ipnet_if_to_sockaddr_dl(netif, buf);
|
|
elem_len += dl_len;
|
|
if (buf != IP_NULL)
|
|
buf = (Ip_u8 *)buf + dl_len;
|
|
/* IPNET_RTA_IFA */
|
|
elem_len += sizeof(struct Ip_sockaddr_in);
|
|
if (buf != IP_NULL)
|
|
buf = ipnet_sysctl_if_add_ip4_addr(buf, addr4->ipaddr_n);
|
|
/* IPNET_RTA_BRD */
|
|
if (IP_BIT_ISSET(addr4->flags, IPNET_IP4_ADDR_FLAG_NETBRD))
|
|
{
|
|
elem_len += sizeof(struct Ip_sockaddr_in);
|
|
if (buf != IP_NULL)
|
|
{
|
|
IP_BIT_SET(ifa->ifam_addrs, IPNET_RTA_BRD);
|
|
buf = ipnet_sysctl_if_add_ip4_addr(buf,
|
|
(addr4->netmask_n & addr4->ipaddr_n) | ~addr4->netmask_n);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (domain == IP_AF_INET6)
|
|
{
|
|
Ipnet_ip6_addr_entry *addr6 = (Ipnet_ip6_addr_entry *)addrx;
|
|
Ip_bool is_scoped = ipnet_ip6_is_scoped_addr(&addr6->addr);
|
|
Ip_u32 scope = netif->ipcom.ifindex;
|
|
struct Ip_in6_addr mask;
|
|
|
|
if (IP_IN6_IS_ADDR_MULTICAST(&addr6->addr) && ifa != IP_NULL)
|
|
IP_BIT_CLR(ifa->ifam_flags, IPNET_RTF_CLONING);
|
|
|
|
/* IPNET_RTA_NETMASK */
|
|
elem_len += sizeof(struct Ip_sockaddr_in6);
|
|
if (buf != IP_NULL)
|
|
{
|
|
ipcom_memset(&mask, 0, sizeof(mask));
|
|
ipnet_route_create_mask(&mask, addr6->prefixlen);
|
|
buf = ipnet_sysctl_if_add_ip6_addr(buf, &mask, is_scoped, ~0u);
|
|
}
|
|
/* IPNET_RTA_IFP */
|
|
dl_len = ipnet_if_to_sockaddr_dl(netif, buf);
|
|
elem_len += dl_len;
|
|
if (buf != IP_NULL)
|
|
buf = (Ip_u8 *)buf + dl_len;
|
|
/* IPNET_RTA_IFA */
|
|
elem_len += sizeof(struct Ip_sockaddr_in6);
|
|
if (buf != IP_NULL)
|
|
buf = ipnet_sysctl_if_add_ip6_addr(buf, &addr6->addr, is_scoped, scope);
|
|
|
|
/* IPNET_RTA_BRD */
|
|
if (IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_POINTOPOINT)
|
|
&& IP_IN6_IS_ADDR_LINK_LOCAL(&addr6->addr))
|
|
{
|
|
struct Ip_in6_ifreq ifreq6;
|
|
struct Ip_sockaddr_in6 *sa6 = (struct Ip_sockaddr_in6 *)&ifreq6.ip_ifr_dstaddr;
|
|
|
|
if (ipnet_if_link_ioctl(netif, IP_SIOCGIFDSTADDR_IN6, &ifreq6) == 0)
|
|
{
|
|
elem_len += sizeof(struct Ip_sockaddr_in6);
|
|
if (buf != IP_NULL)
|
|
{
|
|
IP_BIT_SET(ifa->ifam_addrs, IPNET_RTA_BRD);
|
|
#ifdef IPCOM_USE_SA_LEN
|
|
ip_assert(sa6->sin6_len == sizeof(struct Ip_sockaddr_in6));
|
|
#endif
|
|
buf = ipnet_sysctl_if_add_ip6_addr(buf, &sa6->sin6_addr, IP_TRUE, sa6->sin6_scope_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
if (ifa != IP_NULL)
|
|
ifa->ifam_msglen = (Ip_u16)elem_len;
|
|
*lenp += elem_len;
|
|
return buf;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sysctl_create_ifinfo
|
|
*===========================================================================
|
|
* Description: Creates a IPNET_RTM_IFINFO message for the specified interface.
|
|
* Parameters: buf - buffer where the interface information will be written
|
|
* buflen - the length of 'buf'
|
|
* netif - the interface to create information structure for.
|
|
* Returns: The length needed or copied into 'buf'
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_u16
|
|
ipnet_sysctl_create_ifinfo(void *buf, Ipnet_netif *netif)
|
|
{
|
|
struct Ipnet_if_msghdr *ifm;
|
|
struct Ip_sockaddr_dl *link_addr;
|
|
Ip_u16 len;
|
|
|
|
len = (Ip_u16) (sizeof(struct Ipnet_if_msghdr) + ipnet_if_to_sockaddr_dl(netif, IP_NULL));
|
|
if (buf == IP_NULL)
|
|
return len;
|
|
|
|
ifm = (struct Ipnet_if_msghdr *) buf;
|
|
link_addr = (struct Ip_sockaddr_dl *) (ifm + 1);
|
|
|
|
ifm->ifm_msglen = len;
|
|
ifm->ifm_version = IPNET_RTM_VERSION;
|
|
ifm->ifm_type = IPNET_RTM_IFINFO;
|
|
ifm->ifm_addrs = IPNET_RTA_IFP;
|
|
ifm->ifm_flags = (int) netif->ipcom.flags;
|
|
ifm->ifm_index = netif->ipcom.ifindex;
|
|
|
|
ifm->ifm_data.ifi_type = (Ip_u8) netif->ipcom.type;
|
|
ifm->ifm_data.ifi_addrlen = (Ip_u8) netif->ipcom.link_addr_size;
|
|
ifm->ifm_data.ifi_hdrlen = (Ip_u8) netif->ipcom.link_hdr_size;
|
|
ifm->ifm_data.ifi_link_state = 0;
|
|
ifm->ifm_data.ifi_mtu = netif->ipcom.mtu;
|
|
ifm->ifm_data.ifi_metric = netif->ipcom.metric;
|
|
ifm->ifm_data.ifi_baudrate = 0;
|
|
ifm->ifm_data.ifi_ipackets = netif->ipackets;
|
|
ifm->ifm_data.ifi_ierrors = netif->ierrors;
|
|
ifm->ifm_data.ifi_opackets = netif->opackets;
|
|
ifm->ifm_data.ifi_oerrors = netif->oerrors;
|
|
ifm->ifm_data.ifi_collisions = netif->collisions;
|
|
ifm->ifm_data.ifi_ibytes = netif->ibytes;
|
|
ifm->ifm_data.ifi_obytes = netif->obytes;
|
|
ifm->ifm_data.ifi_imcasts = netif->imcasts;
|
|
ifm->ifm_data.ifi_omcasts = netif->omcasts;
|
|
ifm->ifm_data.ifi_iqdrops = netif->iqdrops;
|
|
ifm->ifm_data.ifi_noproto = netif->noproto;
|
|
ifm->ifm_data.ifi_lastchange.tv_sec = 0;
|
|
ifm->ifm_data.ifi_lastchange.tv_usec = 0;
|
|
|
|
(void)ipnet_if_to_sockaddr_dl(netif, link_addr);
|
|
return len;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_sys_sysctl
|
|
*===========================================================================
|
|
* Description: System control for IPNET.
|
|
* Parameters: name - the hierarchical sysctl name.
|
|
* namelen - the size of the 'name' array.
|
|
* oldp - buffer to where the route entries will be copied
|
|
* oldlenp - [in] the length of 'oldp' buffer
|
|
* [out] the number of bytes copied to 'oldp' buffer or
|
|
* the number of bytes needed (if 'oldp' is IP_NULL).
|
|
* newp - the new value for the variable
|
|
* newlen - the length of the 'newp' buffer.
|
|
* vr - The virtual router to do the syscontrol for.
|
|
* Returns: 0 == success, <0 == error code.
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipnet_sys_sysctl(struct Ipnet_sig_sysctl *sig)
|
|
{
|
|
int ret;
|
|
|
|
if (sig->namelen < 2 || sig->namelen > IP_CTL_MAXNAME)
|
|
{
|
|
ret = -IP_ERRNO_EINVAL;
|
|
goto leave;
|
|
}
|
|
|
|
if ((sig->oldp != IP_NULL && sig->oldlenp == IP_NULL)
|
|
|| (sig->newp != IP_NULL && sig->newlen == 0))
|
|
{
|
|
ret = -IP_ERRNO_EFAULT;
|
|
goto leave;
|
|
}
|
|
|
|
switch (sig->name[0])
|
|
{
|
|
case IP_CTL_NET:
|
|
ret = ipnet_sysctl_net(ipnet_get_effective_vr(),
|
|
sig->name,
|
|
sig->namelen,
|
|
sig->oldp,
|
|
sig->oldlenp,
|
|
sig->newp,
|
|
sig->newlen);
|
|
break;
|
|
default:
|
|
ret = -IP_ERRNO_ENOTDIR;
|
|
break;
|
|
}
|
|
|
|
leave:
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|