1259 lines
38 KiB
C
1259 lines
38 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_configd.c,v $ $Revision: 1.83.10.10 $
|
|
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_configd.c,v $
|
|
* $Author: jsheng $
|
|
* $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_err.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_sysvar.h>
|
|
#include <ipcom_type.h>
|
|
|
|
#include "ipnet.h"
|
|
#include "ipnet_h.h"
|
|
#include "ipnet_loopback.h"
|
|
#include "ipnet_route.h"
|
|
#include "ipnet_routesock.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
#define IPNET_CONFIGD_ADDRSTRLEN_BASE IP_INET6_ADDRSTRLEN
|
|
#else
|
|
#define IPNET_CONFIGD_ADDRSTRLEN_BASE IP_INET_ADDRSTRLEN
|
|
#endif
|
|
|
|
/* Make room for flags */
|
|
#define IPNET_CONFIGD_ADDRSTRLEN (IPNET_CONFIGD_ADDRSTRLEN_BASE + 32)
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IP_PORT_VXWORKS
|
|
IP_GLOBAL char * ipcom_vxworks_boot_devname(void);
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC void
|
|
ipnet_configd_new_if(int rt_sock, Ip_u32 ifindex, const char *ifname);
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Will be posted when the initial configuration has been applied.
|
|
*/
|
|
static Ipcom_sem ipnet_configd_sem;
|
|
|
|
#if defined(IPWRNAD) && defined(IP_PORT_UNIX)
|
|
IP_EXTERN volatile Ip_bool wrnad_mon_running;
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_config_set_if_up
|
|
*===========================================================================
|
|
* Description: Bring up the specified interface.
|
|
* Parameters: sock - a valid socket descriptor
|
|
* ifname - name of the interface to bring up.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_config_set_if_up(int sock, const char *ifname)
|
|
{
|
|
struct Ip_ifreq ifreq;
|
|
|
|
ipcom_memset(&ifreq, 0, sizeof(struct Ip_ifreq));
|
|
ipcom_strncpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
|
|
ifreq.ifr_name[sizeof(ifreq.ifr_name)-1] = '\0';
|
|
|
|
/*
|
|
* Read the current interface flags
|
|
*/
|
|
if (ipcom_socketioctl(sock, IP_SIOCGIFFLAGS, &ifreq) < 0)
|
|
{
|
|
IPCOM_LOG2(ERR, "Failed to read the interface flags for %s: %s",
|
|
ifname,
|
|
ipcom_strerror(ipcom_errno));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Set the IFF_UP flag
|
|
*/
|
|
IP_BIT_SET(ifreq.ip_ifr_flags, IP_IFF_UP);
|
|
|
|
/*
|
|
* Write the interface flags
|
|
*/
|
|
if (ipcom_socketioctl(sock, IP_SIOCSIFFLAGS, &ifreq) < 0)
|
|
IPCOM_LOG2(ERR, "Failed to write the interface flags for %s: %s",
|
|
ifname,
|
|
ipcom_strerror(ipcom_errno));
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_set_ip4_addr
|
|
*===========================================================================
|
|
* Description: Sets the IPv4 address on a network interface.
|
|
* Parameters: sock - a valid socket descriptor.
|
|
* ifindex - index of the interface to set address on
|
|
* addr - IPv4 address in presentation format
|
|
* mask - IPv4 mask in presentation format or IP_NULL to
|
|
* use default mask.
|
|
* Returns: IP_TRUE if the address was added successfully
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET
|
|
IP_STATIC Ip_bool
|
|
ipnet_configd_set_ip4_addr(int sock,
|
|
Ip_u32 ifindex,
|
|
const char *addr,
|
|
const char *mask)
|
|
{
|
|
struct Ip_sockaddr_in *in;
|
|
struct Ip_ifaliasreq ifa;
|
|
struct Ip_ethreq ethreq;
|
|
|
|
ipcom_memset(ðreq, 0, sizeof(struct Ip_ethreq));
|
|
(void)ipcom_if_indextoname(ifindex, ethreq.ethr_name);
|
|
|
|
#ifdef IPNET_USE_RARP
|
|
if (ipcom_strcmp(addr, "rarp") == 0)
|
|
{
|
|
ethreq.ethru.rarp = -1;
|
|
if (ipcom_socketioctl(sock, IP_SIOCXETHSRARP, ðreq) < 0)
|
|
IPCOM_LOG1(ERR, "Failed to enable RARPP on %s", ethreq.ethr_name);
|
|
return IP_FALSE;
|
|
}
|
|
#endif /* IPNET_USE_RARP */
|
|
|
|
if (ipcom_strcmp(addr, "driver") == 0)
|
|
{
|
|
char drvaddr[IP_INET_ADDRSTRLEN];
|
|
char drvmask[IP_INET_ADDRSTRLEN];
|
|
|
|
/*
|
|
* Get the IPv4 address to use from the driver
|
|
*/
|
|
if (ipcom_socketioctl(sock, IP_SIOCXETHGINET, ðreq) < 0)
|
|
return IP_FALSE;
|
|
|
|
/*
|
|
* The above ioctl must return a valid IPv4 address or fail.
|
|
*/
|
|
ip_assert(ethreq.ethru.inet.addr.s_addr != IP_INADDR_ANY);
|
|
|
|
if (ethreq.ethru.inet.addr.s_addr == 0xffffffff)
|
|
return ipnet_configd_set_ip4_addr(sock, ifindex, "dhcp", IP_NULL);
|
|
|
|
ipcom_inet_ntop(IP_AF_INET,
|
|
ðreq.ethru.inet.addr,
|
|
drvaddr,
|
|
sizeof(drvaddr));
|
|
ipcom_inet_ntop(IP_AF_INET,
|
|
ðreq.ethru.inet.mask,
|
|
drvmask,
|
|
sizeof(drvmask));
|
|
return ipnet_configd_set_ip4_addr(sock, ifindex, drvaddr, drvmask);
|
|
}
|
|
|
|
/* Support dhcp */
|
|
if (ipcom_strcmp(addr, "dhcp") == 0)
|
|
{
|
|
struct Ip_ifreq ifr;
|
|
|
|
ipcom_memset(&ifr, 0, sizeof(struct Ip_ifreq));
|
|
(void)ipcom_if_indextoname(ifindex, ifr.ifr_name);
|
|
|
|
ifr.ifr_ifru.ifru_opt = 1;
|
|
if (ipcom_socketioctl(sock, IP_SIOCXSDHCPRUNNING, &ifr) < 0)
|
|
{
|
|
IPCOM_LOG1(ERR, "Failed to enable DHCP on %s", ifr.ifr_name);
|
|
return IP_FALSE;
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
ipcom_memset(&ifa, 0, sizeof(ifa));
|
|
(void)ipcom_if_indextoname(ifindex, ifa.ifra_name);
|
|
in = (struct Ip_sockaddr_in *) &ifa.ifra_addr;
|
|
in->sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(in, sizeof(struct Ip_sockaddr_in));
|
|
(void)ipcom_inet_pton(IP_AF_INET, addr, &in->sin_addr);
|
|
|
|
if (mask != IP_NULL)
|
|
{
|
|
in = (struct Ip_sockaddr_in *) &ifa.ifra_mask;
|
|
in->sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(in, sizeof(struct Ip_sockaddr_in));
|
|
(void)ipcom_inet_pton(IP_AF_INET, mask, &in->sin_addr);
|
|
}
|
|
|
|
if (ipcom_socketioctl(sock, IP_SIOCAIFADDR, &ifa) < 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "Failed to set IPv4 address %s on %s: %s",
|
|
addr,
|
|
ifa.ifra_name,
|
|
ipcom_strerror(ipcom_errno));
|
|
return IP_FALSE;
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_set_ip6_addr
|
|
*===========================================================================
|
|
* Description: Sets the IPv6 address on a network interface.
|
|
* Parameters: sock - a valid socket descriptor.
|
|
* ifindex - index of the interface to set address on
|
|
* addr_and_flags - IPv6 address in presentation format
|
|
* mask - IPv6 mask in presentation format or IP_NULL to
|
|
* use default mask.
|
|
* Returns: IP_TRUE if the address was added successfully
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET6
|
|
IP_STATIC Ip_bool
|
|
ipnet_configd_set_ip6_addr(int sock,
|
|
Ip_u32 ifindex,
|
|
const char *addr,
|
|
const char *mask)
|
|
{
|
|
struct Ip_in6_aliasreq ifareq;
|
|
struct Ip_ethreq ethreq;
|
|
char drvaddr[IP_INET6_ADDRSTRLEN];
|
|
char drvmask[IP_INET6_ADDRSTRLEN];
|
|
|
|
ipcom_memset(&ifareq, 0, sizeof(ifareq));
|
|
ipcom_memset(ðreq, 0, sizeof(struct Ip_ethreq));
|
|
|
|
(void)ipcom_if_indextoname(ifindex, ethreq.ethr_name);
|
|
|
|
for (;;)
|
|
{
|
|
/* Kill initial spaces */
|
|
addr += ipcom_strspn(addr, " \t");
|
|
|
|
/* Check for flags */
|
|
if (ipcom_strncmp(addr, "tentative", 9) == 0)
|
|
{
|
|
ifareq.ifra_flags |= IP_IN6_IFF_TENTATIVE;
|
|
addr += 9;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
|
|
if (ipcom_strcmp(addr, "driver") == 0)
|
|
{
|
|
struct Ip_in6_addr netmask;
|
|
|
|
/*
|
|
* Get the IPv6 address to use from the driver
|
|
*/
|
|
if (ipcom_socketioctl(sock, IP_SIOCXETHGINET6, ðreq) < 0)
|
|
return IP_FALSE;
|
|
/*
|
|
* The above ioctl must return a valid IPv6 address or fail.
|
|
*/
|
|
ip_assert(!IP_IN6_IS_ADDR_UNSPECIFIED(ðreq.ethru.inet6.addr));
|
|
|
|
ipcom_inet_ntop(IP_AF_INET6,
|
|
ðreq.ethru.inet6.addr,
|
|
drvaddr,
|
|
sizeof(drvaddr));
|
|
|
|
ipcom_memset(&netmask, 0, sizeof(netmask));
|
|
ipnet_route_create_mask(&netmask, ethreq.ethru.inet6.prefixlen);
|
|
ipcom_inet_ntop(IP_AF_INET6,
|
|
&netmask,
|
|
drvmask,
|
|
sizeof(drvmask));
|
|
|
|
/*
|
|
return ipnet_configd_set_ip6_addr(sock, ifindex, drvaddr, drvmask);
|
|
*/
|
|
addr = drvaddr;
|
|
mask = drvmask;
|
|
}
|
|
|
|
(void)ipcom_if_indextoname(ifindex, ifareq.ifra_name);
|
|
|
|
ifareq.ifra_addr.sin6_family = IP_AF_INET6;
|
|
IPCOM_SA_LEN_SET(&ifareq.ifra_addr, sizeof(struct Ip_sockaddr_in6));
|
|
if (ipcom_inet_pton(IP_AF_INET6, addr, &ifareq.ifra_addr.sin6_addr) != 1)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"Failed to set IPv6 address %s on %s since the address format is invalid",
|
|
addr,
|
|
ifareq.ifra_name);
|
|
return IP_FALSE;
|
|
}
|
|
|
|
if (mask == IP_NULL)
|
|
{
|
|
/*
|
|
* Use default mask
|
|
*/
|
|
if (IP_IN6_IS_ADDR_MULTICAST(&ifareq.ifra_addr.sin6_addr))
|
|
mask = "ffff::";
|
|
else if (IP_IN6_IS_ADDR_LOOPBACK(&ifareq.ifra_addr.sin6_addr))
|
|
mask = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
|
|
else
|
|
mask = "ffff:ffff:ffff:ffff::";
|
|
}
|
|
|
|
ifareq.ifra_prefixmask.sin6_family = IP_AF_INET6;
|
|
IPCOM_SA_LEN_SET(&ifareq.ifra_prefixmask, sizeof(struct Ip_sockaddr_in6));
|
|
(void)ipcom_inet_pton(IP_AF_INET6, mask, &ifareq.ifra_prefixmask.sin6_addr);
|
|
|
|
/* TODO: make it configurable as to when tentative should be used */
|
|
/* ifareq.ifra_flags = IP_IN6_IFF_TENTATIVE; */
|
|
ifareq.ifra_lifetime.ia6t_preferred = (Ip_time_t)IPCOM_ADDR_INFINITE;
|
|
ifareq.ifra_lifetime.ia6t_expire = (Ip_time_t)IPCOM_ADDR_INFINITE;
|
|
|
|
if (ipcom_socketioctl(sock, IP_SIOCAIFADDR_IN6, &ifareq) < 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "Failed to set IPv6 address %s on %s: %s",
|
|
addr,
|
|
ifareq.ifra_name,
|
|
ipcom_strerror(ipcom_errno));
|
|
return IP_FALSE;
|
|
}
|
|
return IP_TRUE;
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_set_addr
|
|
*===========================================================================
|
|
* Description: Sets an IP address to an network interface.
|
|
* Parameters: rt_sock - route socket
|
|
* domain - IP_AF_INET or IP_AF_INET6
|
|
* ifindex - interface index of the interface to set
|
|
* address on
|
|
* addr - IP address to set
|
|
* mask - network mask to set or IP_NULL
|
|
* Returns: IP_TRUE if the address was successfully added.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipnet_configd_set_addr(int rt_sock,
|
|
int domain,
|
|
Ip_u32 ifindex,
|
|
const char *addr,
|
|
const char *mask)
|
|
{
|
|
switch (domain)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
return ipnet_configd_set_ip4_addr(rt_sock, ifindex, addr, mask);
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
return ipnet_configd_set_ip6_addr(rt_sock, ifindex, addr, mask);
|
|
#endif
|
|
}
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_add_default_gw
|
|
*===========================================================================
|
|
* Description: Adds a default gateway route entry
|
|
* Parameters: rt_sock - AF_ROUTE socket.
|
|
* domain - IP_AF_INET or IP_AF_INET6
|
|
* ifindex - egress interface used to reach the gateway
|
|
* gateway - presentation form of the gateway address.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_configd_add_default_gw(int rt_sock,
|
|
int domain,
|
|
Ip_u32 ifindex,
|
|
const char *gateway)
|
|
{
|
|
Ip_pid_t pid;
|
|
Ip_u32 seq;
|
|
Ip_size_t sa_len;
|
|
struct Ipnet_rt_msghdr *rt;
|
|
union Ip_sockaddr_union *dst;
|
|
union Ip_sockaddr_union *mask;
|
|
union Ip_sockaddr_union *gw;
|
|
char buf[sizeof(struct Ipnet_rt_msghdr)
|
|
+ 3 * sizeof(union Ip_sockaddr_union)];
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (domain == IP_AF_INET
|
|
&& ipcom_strcmp("driver", gateway) == 0)
|
|
{
|
|
struct Ip_ethreq ethreq;
|
|
|
|
ipcom_memset(ðreq, 0, sizeof(struct Ip_ethreq));
|
|
(void)ipcom_if_indextoname(ifindex, ethreq.ethr_name);
|
|
|
|
/*
|
|
* Get the IPv4 gateway from the driver
|
|
*/
|
|
if (ipcom_socketioctl(rt_sock, IP_SIOCXETHGINET, ðreq) < 0)
|
|
/*
|
|
* Return silently, setting the gateway to "driver" just
|
|
* means that we should check if the driver has specified
|
|
* a gateway.
|
|
*/
|
|
return;
|
|
|
|
if (ethreq.ethru.inet.gateway.s_addr != IP_INADDR_ANY
|
|
&ðreq.ethru.inet.gateway.s_addr != 0xffffffff)
|
|
{
|
|
char drvgw[IP_INET_ADDRSTRLEN];
|
|
|
|
ipcom_inet_ntop(IP_AF_INET,
|
|
ðreq.ethru.inet.gateway,
|
|
drvgw,
|
|
sizeof(drvgw));
|
|
ipnet_configd_add_default_gw(rt_sock, IP_AF_INET, ifindex, drvgw);
|
|
}
|
|
/*
|
|
* else: static configuration says gateway should be read from
|
|
* the driver/BSP/persistant storage, but no gateway has been
|
|
* specified there.
|
|
*/
|
|
|
|
return;
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (domain == IP_AF_INET6
|
|
&& ipcom_strcmp("driver", gateway) == 0)
|
|
/*
|
|
* No support for reading the IPv6 gateway from the driver
|
|
* yet.
|
|
*/
|
|
return;
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
pid = ipcom_getpid();
|
|
seq = ipcom_random();
|
|
|
|
ipcom_memset(buf, 0, sizeof(buf));
|
|
|
|
/*
|
|
* Initialize the route message header.
|
|
*/
|
|
rt = (struct Ipnet_rt_msghdr *) buf;
|
|
rt->rtm_msglen = sizeof(struct Ipnet_rt_msghdr);
|
|
rt->rtm_version = IPNET_RTM_VERSION;
|
|
rt->rtm_type = IPNET_RTM_ADD;
|
|
rt->rtm_flags = (IPNET_RTF_UP
|
|
| IPNET_RTF_DONE
|
|
| IPNET_RTF_STATIC
|
|
| IPNET_RTF_GATEWAY);
|
|
rt->rtm_addrs = (IPNET_RTA_DST
|
|
| IPNET_RTA_NETMASK
|
|
| IPNET_RTA_GATEWAY);
|
|
rt->rtm_index = ifindex;
|
|
rt->rtm_pid = pid;
|
|
rt->rtm_seq = seq;
|
|
rt->rtm_table = IPCOM_ROUTE_TABLE_DEFAULT;
|
|
|
|
dst = (union Ip_sockaddr_union *) (rt + 1);
|
|
|
|
switch (domain)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
gw = (union Ip_sockaddr_union *) (&dst->sin + 1);
|
|
mask = (union Ip_sockaddr_union *) (&gw->sin + 1);
|
|
sa_len = sizeof(struct Ip_sockaddr_in);
|
|
break;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
gw = (union Ip_sockaddr_union *) (&dst->sin6 + 1);
|
|
mask = (union Ip_sockaddr_union *) (&gw->sin6 + 1);
|
|
sa_len = sizeof(struct Ip_sockaddr_in6);
|
|
break;
|
|
#endif
|
|
default:
|
|
gw = IP_NULL;
|
|
mask = IP_NULL;
|
|
sa_len = 0;
|
|
IP_PANIC();
|
|
}
|
|
|
|
/*
|
|
* The message contains 3 socket addresses: dst, netmask and
|
|
* gateway.
|
|
*/
|
|
rt->rtm_msglen = (Ip_u16) (rt->rtm_msglen + (3 * sa_len));
|
|
|
|
/*
|
|
* Set destination address (0.0.0.0 or ::)
|
|
*/
|
|
dst->sa.sa_family = (Ip_sa_family_t)domain;
|
|
IPCOM_SA_LEN_SET(&dst->sa, sa_len);
|
|
|
|
/*
|
|
* Set mask (0.0.0.0 or /0)
|
|
*/
|
|
/* mask points to the wanted buffer address correctly */
|
|
/* coverity[overrun-local] */
|
|
mask->sa.sa_family = (Ip_sa_family_t)domain;
|
|
IPCOM_SA_LEN_SET(&mask->sa, sa_len);
|
|
|
|
/*
|
|
* Set the gateway address
|
|
*/
|
|
if(ipcom_getsockaddrbyaddr(domain, gateway, &gw->sa))
|
|
{
|
|
IPCOM_LOG1(ERR, "ipcom_getsockaddrbyaddr failed gw: %s",gateway);
|
|
return;
|
|
}
|
|
|
|
if (ipcom_send(rt_sock, rt, rt->rtm_msglen, 0) < 0)
|
|
{
|
|
IPCOM_LOG1(ERR, "Failed send to AF_ROUTE socket: %s", ipcom_strerror(ipcom_errno));
|
|
IP_PANIC();
|
|
return;
|
|
}
|
|
|
|
do
|
|
{
|
|
Ip_ssize_t bytes_read;
|
|
|
|
bytes_read = ipcom_recv(rt_sock, rt, sizeof(buf), 0);
|
|
if (bytes_read < 0)
|
|
{
|
|
IPCOM_LOG1(ERR, "Failed read from AF_ROUTE socket: %s", ipcom_strerror(ipcom_errno));
|
|
return;
|
|
}
|
|
|
|
if (rt->rtm_type == IPNET_RTM_IFANNOUNCE)
|
|
{
|
|
struct Ipnet_if_announcemsghdr *if_announce;
|
|
|
|
/*
|
|
* New interface attached while waiting for result of
|
|
* gateway add.
|
|
*/
|
|
if_announce = (struct Ipnet_if_announcemsghdr *) rt;
|
|
ipnet_configd_new_if(rt_sock,
|
|
if_announce->ifan_index,
|
|
if_announce->ifan_name);
|
|
}
|
|
} while (rt->rtm_type != IPNET_RTM_ADD
|
|
|| rt->rtm_seq != seq
|
|
|| rt->rtm_pid != pid);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_new_if
|
|
*===========================================================================
|
|
* Description: Configures a network interface that just got attached.
|
|
* Parameters: rt_sock - an AF_ROUTE socket
|
|
* ifindex - interface index of the new interface
|
|
* ifname - interface name of the new interface.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_configd_new_if(int rt_sock, Ip_u32 ifindex, const char *ifname)
|
|
{
|
|
char sysvar_name[IP_IFNAMSIZ + 20];
|
|
char addr[IPNET_CONFIGD_ADDRSTRLEN];
|
|
char mask_buf[IPNET_CONFIGD_ADDRSTRLEN];
|
|
char *mask;
|
|
char gateway[IPNET_CONFIGD_ADDRSTRLEN];
|
|
Ip_size_t len;
|
|
int family[] = {
|
|
#ifdef IPCOM_USE_INET
|
|
IP_AF_INET,
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
IP_AF_INET6,
|
|
#endif
|
|
0
|
|
};
|
|
int f;
|
|
Ip_bool bring_if_up = IP_FALSE;
|
|
|
|
for (f = 0; family[f] > 0; f++)
|
|
{
|
|
const char *family_str;
|
|
unsigned n;
|
|
|
|
if (family[f] == IP_AF_INET)
|
|
family_str = "inet";
|
|
else
|
|
family_str = "inet6";
|
|
|
|
for (n = 1; ; n++)
|
|
{
|
|
/*
|
|
* Configure IP address and mask
|
|
*/
|
|
ipcom_sprintf(sysvar_name, "%s.%s.%u.addr", ifname, family_str, n);
|
|
len = sizeof(addr);
|
|
if (ipcom_sysvar_get(sysvar_name, addr, &len) == IP_NULL)
|
|
{
|
|
#ifdef IP_PORT_UNIX
|
|
/*
|
|
* No address configured for this interface, default
|
|
* to ask the driver for the configuration. This is
|
|
* done so that any configuration that is passed to
|
|
* the simulator on the command line will be used if
|
|
* no override is specified in ipnet_conf_interfaces
|
|
* in file <ipnet>/config/ipnet_config.c
|
|
*/
|
|
if (n == 1)
|
|
{
|
|
/*
|
|
* Check if the driver can return the IP
|
|
* configuration.
|
|
*/
|
|
bring_if_up |= ipnet_configd_set_addr(rt_sock,
|
|
family[f],
|
|
ifindex,
|
|
"driver",
|
|
"driver");
|
|
ipnet_configd_add_default_gw(rt_sock,
|
|
family[f],
|
|
ifindex,
|
|
"driver");
|
|
}
|
|
#endif /* IP_PORT_UNIX */
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Check for prefixlen/netmask
|
|
*/
|
|
ipcom_sprintf(sysvar_name, "%s.%s.%u.netmask", ifname, family_str, n);
|
|
len = sizeof(mask_buf);
|
|
mask = mask_buf;
|
|
if (ipcom_sysvar_get(sysvar_name, mask, &len) == IP_NULL)
|
|
{
|
|
union Ip_in_addr_union mask_addr;
|
|
|
|
ipcom_sprintf(sysvar_name, "%s.%s.%u.prefixlen", ifname, family_str, n);
|
|
len = sizeof(mask_buf);
|
|
if (ipcom_sysvar_get(sysvar_name, mask, &len) == IP_NULL)
|
|
{
|
|
/*
|
|
* Use default mask
|
|
*/
|
|
mask = IP_NULL;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Convert prefix length to dotted quad (IPv4) or hex
|
|
* sequence (IPv6)
|
|
*/
|
|
ipcom_memset(&mask_addr, 0, sizeof(mask_addr));
|
|
ipnet_route_create_mask(&mask_addr, ipcom_atoi(mask));
|
|
ipcom_inet_ntop(family[f], &mask_addr, mask, sizeof(mask_buf));
|
|
}
|
|
}
|
|
|
|
bring_if_up |= ipnet_configd_set_addr(rt_sock, family[f], ifindex, addr, mask);
|
|
|
|
/*
|
|
* Add default gateway, if specified
|
|
*/
|
|
ipcom_sprintf(sysvar_name, "%s.%s.%u.gateway", ifname, family_str, n);
|
|
len = sizeof(gateway);
|
|
if (ipcom_sysvar_get(sysvar_name, gateway, &len))
|
|
ipnet_configd_add_default_gw(rt_sock, family[f], ifindex, gateway);
|
|
}
|
|
}
|
|
|
|
if (!bring_if_up)
|
|
{
|
|
ipcom_sprintf(sysvar_name, "%s.up", ifname);
|
|
bring_if_up = ipcom_sysvar_get_as_int(sysvar_name, IP_FALSE);
|
|
}
|
|
|
|
if (bring_if_up)
|
|
ipnet_config_set_if_up(rt_sock, ifname);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd
|
|
*===========================================================================
|
|
* Description: Daemon that listens for interfaces being attached to
|
|
* the stack. Tries to configure them as soons as they
|
|
* are attached.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC
|
|
IPCOM_PROCESS(ipnet_configd)
|
|
{
|
|
int rt_sock;
|
|
struct Ip_if_nameindex *ni;
|
|
Ip_ssize_t r;
|
|
|
|
ipcom_proc_init();
|
|
|
|
rt_sock = ipcom_socket(IP_AF_ROUTE, IP_SOCK_RAW, 0);
|
|
if (rt_sock < 0)
|
|
/*
|
|
* The configuration daemon requires support for AF_ROUTE.
|
|
*/
|
|
IP_PANIC();
|
|
|
|
r = 65535;
|
|
(void)ipcom_setsockopt(rt_sock, IP_SOL_SOCKET, IP_SO_RCVBUF, &r, sizeof(r));
|
|
|
|
ni = ipcom_if_nameindex();
|
|
if (ni == IP_NULL)
|
|
/*
|
|
* Out-of-memory
|
|
*/
|
|
IP_PANIC();
|
|
|
|
/*
|
|
* Configure all interfaces that has been attached before this
|
|
* daemon started.
|
|
*/
|
|
for (r = 0; ni[r].if_index > 0; r++)
|
|
ipnet_configd_new_if(rt_sock,
|
|
ni[r].if_index,
|
|
ni[r].if_name);
|
|
|
|
/*
|
|
* Initial configuration is done
|
|
*/
|
|
ipcom_sem_post(ipnet_configd_sem);
|
|
|
|
for (;;)
|
|
{
|
|
struct Ipnet_if_announcemsghdr msg;
|
|
r = ipcom_recv(rt_sock, &msg, sizeof(msg), 0);
|
|
if (r < 0)
|
|
{
|
|
IPCOM_LOG1(ERR, "Failed to read AF_ROUTE socket: %s", ipcom_strerror(ipcom_errno));
|
|
break;
|
|
}
|
|
if (r != sizeof(msg)
|
|
|| msg.ifan_type != IPNET_RTM_IFANNOUNCE)
|
|
/*
|
|
* Wrong message type
|
|
*/
|
|
continue;
|
|
|
|
if (ni != IP_NULL)
|
|
{
|
|
/*
|
|
* First time an if announce message is seen, check if
|
|
* this interface has already been configured before
|
|
* entering the for(;;) loop.
|
|
*/
|
|
for (r = 0; ni[r].if_index > 0; r++)
|
|
if (ni[r].if_index == msg.ifan_index)
|
|
/*
|
|
* Don't configure this interface since it has
|
|
* already been configured.
|
|
*/
|
|
msg.ifan_what = IPNET_IFAN_DEPARTURE;
|
|
ipcom_if_freenameindex(ni);
|
|
ni = IP_NULL;
|
|
}
|
|
|
|
if (msg.ifan_what == IPNET_IFAN_ARRIVAL)
|
|
{
|
|
#if defined(IPWRNAD) && defined(IP_PORT_UNIX)
|
|
while (!wrnad_mon_running)
|
|
ipcom_sleep(1);
|
|
#endif
|
|
ipnet_configd_new_if(rt_sock,
|
|
msg.ifan_index,
|
|
msg.ifan_name);
|
|
}
|
|
}
|
|
|
|
ipcom_socketclose(rt_sock);
|
|
ipcom_proc_exit();
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_bring_if_up
|
|
*===========================================================================
|
|
* Description: Makes sure that the interface is brough put if attached.
|
|
* Parameters: ifname - an interface name
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_configd_bring_if_up(const char *ifname)
|
|
{
|
|
char sysvar_name[IP_IFNAMSIZ + 4];
|
|
Ip_err errno;
|
|
|
|
ipcom_sprintf(sysvar_name, "%s.up", ifname);
|
|
errno = ipcom_sysvar_set(sysvar_name, "1", IPCOM_SYSVAR_FLAG_OVERWRITE);
|
|
if(errno)
|
|
IPCOM_LOG3(ERR,
|
|
"set sysvar '%s' for %s failed errno %d",
|
|
sysvar_name,
|
|
"1",
|
|
errno);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_get_next_n
|
|
*===========================================================================
|
|
* Description: Returns the next available address sequence number
|
|
* Parameters: ifname - an interface name
|
|
* family_name - "inet" or "inet6"
|
|
* Returns: next available address sequence number
|
|
*
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipnet_configd_get_next_n(const char *ifname, const char *family_name)
|
|
{
|
|
char sysvar_name[IP_IFNAMSIZ + 20];
|
|
char addr[IPNET_CONFIGD_ADDRSTRLEN];
|
|
Ip_size_t len;
|
|
unsigned n;
|
|
|
|
for (n = 1; ;n++)
|
|
{
|
|
ipcom_sprintf(sysvar_name, "%s.%s.%u.addr",
|
|
ifname,
|
|
family_name,
|
|
n);
|
|
len = sizeof(addr);
|
|
if (ipcom_sysvar_get(sysvar_name, addr, &len) == IP_NULL)
|
|
break;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_get_value
|
|
*===========================================================================
|
|
* Description: Returns the value part from a string with format
|
|
* "<key> <value>".
|
|
* Parameters: key_and_value - a key or key + value string.
|
|
* Returns: A pointer to the value or IP_NULL if no value is present.
|
|
*
|
|
*/
|
|
IP_STATIC const char *
|
|
ipnet_configd_get_value(const char *key_and_value)
|
|
{
|
|
while (*key_and_value != '\0'
|
|
&& !ipcom_isspace(*key_and_value))
|
|
key_and_value++;
|
|
|
|
if (*key_and_value == '\0')
|
|
/*
|
|
* No value present.
|
|
*/
|
|
return IP_NULL;
|
|
|
|
while (ipcom_isspace(*key_and_value))
|
|
key_and_value++;
|
|
|
|
if (ipcom_strlen(key_and_value) == 0)
|
|
/*
|
|
* No value present.
|
|
*/
|
|
return IP_NULL;
|
|
|
|
return key_and_value;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_tr_value
|
|
*===========================================================================
|
|
* Description: Translates an IPv4 address specification to a sysvar
|
|
* with format <ifname>.inet.<N>.addr = <addr>
|
|
* Parameters: ip4_spec - string with format "inet <addr>"
|
|
* ifname - name of the interface
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_configd_tr_value(const char *key_and_value,
|
|
const char *family_name,
|
|
const char *value_name,
|
|
const char *ifname)
|
|
{
|
|
const char *value;
|
|
char sysvar_name[IP_IFNAMSIZ + 20];
|
|
Ip_err errno;
|
|
|
|
value = ipnet_configd_get_value(key_and_value);
|
|
if (value == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"Invalid specification '%s' for %s",
|
|
key_and_value,
|
|
ifname);
|
|
return;
|
|
}
|
|
|
|
ipcom_sprintf(sysvar_name, "%s.%s.1.%s",
|
|
ifname,
|
|
family_name,
|
|
value_name);
|
|
errno = ipcom_sysvar_set(sysvar_name, value, IPCOM_SYSVAR_FLAG_OVERWRITE);
|
|
if(errno)
|
|
IPCOM_LOG3(ERR,
|
|
"set sysvar '%s' for %s failed errno %d",
|
|
sysvar_name,
|
|
value,
|
|
errno);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_tr_addr
|
|
*===========================================================================
|
|
* Description: Translates the old IP address specification to the new model
|
|
* Parameters: key_and_value - address specification
|
|
* family_name - 'inet' or 'inet6' for IPv4 or IPv6
|
|
* ifname - name of the network interface.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_configd_tr_addr(const char *key_and_value,
|
|
const char *family_name,
|
|
const char *ifname)
|
|
{
|
|
const char *prefixlen;
|
|
char addr[IPNET_CONFIGD_ADDRSTRLEN];
|
|
char sysvar_name[IP_IFNAMSIZ + 20];
|
|
int i = 0;
|
|
unsigned n = ipnet_configd_get_next_n(ifname, family_name);
|
|
Ip_err errno;
|
|
|
|
prefixlen = ipnet_configd_get_value(key_and_value);
|
|
if (prefixlen == IP_NULL)
|
|
{
|
|
IPCOM_LOG2(ERR,
|
|
"Invalid address specification '%s' for %s",
|
|
key_and_value,
|
|
ifname);
|
|
return;
|
|
}
|
|
|
|
while (*prefixlen != '\0' && *prefixlen != '/')
|
|
/*
|
|
* Copy the address part
|
|
*/
|
|
addr[i++] = *(prefixlen++);
|
|
addr[i] = '\0';
|
|
|
|
/*
|
|
* Set the address
|
|
*/
|
|
ipcom_sprintf(sysvar_name, "%s.%s.%u.addr", ifname, family_name, n);
|
|
errno = ipcom_sysvar_set(sysvar_name, addr, IPCOM_SYSVAR_FLAG_OVERWRITE);
|
|
if(errno)
|
|
IPCOM_LOG3(ERR,
|
|
"set sysvar '%s' for %s failed errno %d",
|
|
sysvar_name,
|
|
addr,
|
|
errno);
|
|
|
|
if (*prefixlen == '/')
|
|
{
|
|
/*
|
|
* Set the prefixlen
|
|
*/
|
|
ipcom_sprintf(sysvar_name, "%s.%s.%u.prefixlen", ifname, family_name, n);
|
|
errno = ipcom_sysvar_set(sysvar_name, ++prefixlen, IPCOM_SYSVAR_FLAG_OVERWRITE);
|
|
if(errno)
|
|
IPCOM_LOG3(ERR,
|
|
"set sysvar '%s' for %s failed errno %d",
|
|
sysvar_name,
|
|
prefixlen,
|
|
errno);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_get_devname
|
|
*===========================================================================
|
|
* Description: Returns the name of the device driver to use.
|
|
* Parameters: devname_spec - device name specification.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC const char *
|
|
ipnet_configd_get_devname(const char *devname_spec)
|
|
{
|
|
const char *devname;
|
|
|
|
devname = ipnet_configd_get_value(devname_spec);
|
|
#ifdef IP_PORT_VXWORKS
|
|
if (devname != IP_NULL
|
|
&& ipcom_strcmp(devname, "driver") == 0)
|
|
{
|
|
/*
|
|
* Use the driver name of the boot device
|
|
*/
|
|
devname = ipcom_vxworks_boot_devname();
|
|
}
|
|
#endif /* IP_PORT_VXWORKS */
|
|
|
|
return devname;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_merge_ifconf
|
|
*===========================================================================
|
|
* Description: Merges the configuration in ipnet_conf_interfaces with
|
|
* the sysvar configuration. The union of the configurations
|
|
* is stored as sysvars.
|
|
* Parameters: if_conf - pointer to the old interface specification
|
|
* line - the current line we are processing in 'if_conf'
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_configd_merge_ifconf(const char **if_conf, int line)
|
|
{
|
|
const char *ifname;
|
|
|
|
if (if_conf[line] == IP_NULL)
|
|
/*
|
|
* No more interface definitions to process
|
|
*/
|
|
return;
|
|
|
|
if (ipcom_strncmp("ifname", if_conf[line], 6) != 0)
|
|
{
|
|
/*
|
|
* First line of an interface definition must be
|
|
* "ifname <ifname>"
|
|
*/
|
|
IPCOM_LOG2(ERR,
|
|
"Interface definition at line %d (%s) does not start with \"ifname\"",
|
|
line,
|
|
if_conf[line]);
|
|
return;
|
|
}
|
|
|
|
ifname = ipnet_configd_get_value(if_conf[line]);
|
|
if (ifname == IP_NULL)
|
|
{
|
|
/*
|
|
* No explicit interface name, it should be same as the name
|
|
* of the driver.
|
|
*/
|
|
ifname = ipnet_configd_get_devname(if_conf[++line]);
|
|
if (ifname == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"No interface name specified for '%s' and 'devname' was not found",
|
|
if_conf[line-1]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
ipnet_configd_bring_if_up(ifname);
|
|
|
|
/*
|
|
* Translate addresses
|
|
*/
|
|
while (if_conf[++line] != IP_NULL)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
if (ipcom_strncmp(if_conf[line], "inet ", 5) == 0)
|
|
ipnet_configd_tr_addr(if_conf[line], "inet", ifname);
|
|
if (ipcom_strncmp(if_conf[line], "gateway ", 8) == 0)
|
|
ipnet_configd_tr_value(if_conf[line], "inet", "gateway", ifname);
|
|
#endif /* IPCOM_USE_INET */
|
|
#ifdef IPCOM_USE_INET6
|
|
if (ipcom_strncmp(if_conf[line], "inet6 ", 6) == 0)
|
|
ipnet_configd_tr_addr(if_conf[line], "inet6", ifname);
|
|
if (ipcom_strncmp(if_conf[line], "gateway6 ", 9) == 0)
|
|
ipnet_configd_tr_value(if_conf[line], "inet6", "gateway", ifname);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Check for more interfaces
|
|
*/
|
|
ipnet_configd_merge_ifconf(if_conf, line + 1);
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_configd_start
|
|
*===========================================================================
|
|
* Description: Starts the stack configuration daemon.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipnet_configd_start()
|
|
{
|
|
/*
|
|
* Merge the configuration information into the new, sysvar
|
|
* based, method.
|
|
* <ifname>.inet.<N>.[addr|netmask|gateway]
|
|
* <ifname>.inet6.<N.[addr|prefixlen|gateway]
|
|
* N number from 1 and up to allow more than one address per interface
|
|
*/
|
|
ipnet_configd_merge_ifconf(ipnet_conf_interfaces, 0);
|
|
|
|
if (ipcom_sem_create(&ipnet_configd_sem, 0) != IPCOM_SUCCESS)
|
|
IP_PANIC();
|
|
|
|
if (ipcom_proc_acreate("tNetConf",
|
|
ipnet_configd,
|
|
IP_NULL,
|
|
IP_NULL) != IPCOM_SUCCESS)
|
|
{
|
|
IP_PANIC();
|
|
return -IP_ERRNO_ENOMEM;
|
|
}
|
|
|
|
/*
|
|
* Wait for the initial configuration to be applied.
|
|
*/
|
|
ipcom_sem_wait(ipnet_configd_sem);
|
|
ipcom_sem_delete(&ipnet_configd_sem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|