#include <zebra.h>
+#ifdef SUNOS_5
+
#include "if.h"
#include "sockunion.h"
#include "prefix.h"
#include "privs.h"
#include "vrf.h"
#include "vty.h"
+#include "lib_errors.h"
#include "zebra/interface.h"
#include "zebra/ioctl_solaris.h"
#include "zebra/rib.h"
-static int if_get_addr (struct interface *, struct sockaddr *, const char *);
-static void interface_info_ioctl (struct interface *);
+static int if_get_addr(struct interface *, struct sockaddr *, const char *);
+static void interface_info_ioctl(struct interface *);
extern struct zebra_privs_t zserv_privs;
-static int
-interface_list_ioctl (int af)
+static int interface_list_ioctl(int af)
{
- int ret;
- int sock;
+ int ret;
+ int sock;
#define IFNUM_BASE 32
- struct lifnum lifn;
- int ifnum;
- struct lifreq *lifreq;
- struct lifconf lifconf;
- struct interface *ifp;
- int n;
- int save_errno;
- size_t needed, lastneeded = 0;
- char *buf = NULL;
-
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
-
- sock = socket (af, SOCK_DGRAM, 0);
- if (sock < 0)
- {
- zlog_warn ("Can't make %s socket stream: %s",
- (af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno));
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
-
- return -1;
- }
-
-calculate_lifc_len: /* must hold privileges to enter here */
- lifn.lifn_family = af;
- lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
- ret = ioctl (sock, SIOCGLIFNUM, &lifn);
- save_errno = errno;
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
-
- if (ret < 0)
- {
- zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s",
- safe_strerror (save_errno));
- close (sock);
- return -1;
- }
- ifnum = lifn.lifn_count;
-
- /*
- * When calculating the buffer size needed, add a small number
- * of interfaces to those we counted. We do this to capture
- * the interface status of potential interfaces which may have
- * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
- */
- needed = (ifnum + 4) * sizeof (struct lifreq);
- if (needed > lastneeded || needed < lastneeded / 2)
- {
- if (buf != NULL)
- XFREE (MTYPE_TMP, buf);
- if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL)
- {
- zlog_warn ("interface_list_ioctl: malloc failed");
- close (sock);
- return -1;
- }
- }
- lastneeded = needed;
-
- lifconf.lifc_family = af;
- lifconf.lifc_flags = LIFC_NOXMIT;
- lifconf.lifc_len = needed;
- lifconf.lifc_buf = buf;
-
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
-
- ret = ioctl (sock, SIOCGLIFCONF, &lifconf);
-
- if (ret < 0)
- {
- if (errno == EINVAL)
- goto calculate_lifc_len; /* deliberately hold privileges */
-
- zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno));
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
-
- goto end;
- }
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
-
- /* Allocate interface. */
- lifreq = lifconf.lifc_req;
-
- for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq))
- {
- /* we treat Solaris logical interfaces as addresses, because that is
- * how PF_ROUTE on Solaris treats them. Hence we can not directly use
- * the lifreq_name to get the ifp. We need to normalise the name
- * before attempting get.
- *
- * Solaris logical interface names are in the form of:
- * <interface name>:<logical interface id>
- */
- unsigned int normallen = 0;
- uint64_t lifflags;
-
- /* We should exclude ~IFF_UP interfaces, as we'll find out about them
- * coming up later through RTM_NEWADDR message on the route socket.
- */
- if (if_get_flags_direct (lifreq->lifr_name, &lifflags,
- lifreq->lifr_addr.ss_family)
- || !CHECK_FLAG (lifflags, IFF_UP))
- {
- lifreq++;
- continue;
- }
-
- /* Find the normalised name */
- while ( (normallen < sizeof(lifreq->lifr_name))
- && ( *(lifreq->lifr_name + normallen) != '\0')
- && ( *(lifreq->lifr_name + normallen) != ':') )
- normallen++;
-
- ifp = if_get_by_name_len(lifreq->lifr_name, normallen, VRF_DEFAULT, 0);
-
- if (lifreq->lifr_addr.ss_family == AF_INET)
- ifp->flags |= IFF_IPV4;
-
- if (lifreq->lifr_addr.ss_family == AF_INET6)
- {
- ifp->flags |= IFF_IPV6;
- }
-
- if_add_update (ifp);
-
- interface_info_ioctl (ifp);
-
- /* If a logical interface pass the full name so it can be
- * as a label on the address
- */
- if ( *(lifreq->lifr_name + normallen) != '\0')
- if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr,
- lifreq->lifr_name);
- else
- if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL);
-
- /* Poke the interface flags. Lets IFF_UP mangling kick in */
- if_flags_update (ifp, ifp->flags);
-
- lifreq++;
- }
+ struct lifnum lifn;
+ int ifnum;
+ struct lifreq *lifreq;
+ struct lifconf lifconf;
+ struct interface *ifp;
+ int n;
+ int save_errno;
+ size_t needed, lastneeded = 0;
+ char *buf = NULL;
+
+ frr_elevate_privs(&zserv_privs) {
+
+ sock = socket(af, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ zlog_warn("Can't make %s socket stream: %s",
+ (af == AF_INET ? "AF_INET" : "AF_INET6"),
+ safe_strerror(errno));
+
+ return -1;
+ }
+
+calculate_lifc_len: /* must hold privileges to enter here */
+ lifn.lifn_family = af;
+ lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
+ ret = ioctl(sock, SIOCGLIFNUM, &lifn);
+ save_errno = errno;
+
+ }
+
+ if (ret < 0) {
+ zlog_warn("interface_list_ioctl: SIOCGLIFNUM failed %s",
+ safe_strerror(save_errno));
+ close(sock);
+ return -1;
+ }
+ ifnum = lifn.lifn_count;
+
+ /*
+ * When calculating the buffer size needed, add a small number
+ * of interfaces to those we counted. We do this to capture
+ * the interface status of potential interfaces which may have
+ * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
+ */
+ needed = (ifnum + 4) * sizeof(struct lifreq);
+ if (needed > lastneeded || needed < lastneeded / 2) {
+ if (buf != NULL)
+ XFREE(MTYPE_TMP, buf);
+ buf = XMALLOC(MTYPE_TMP, needed);
+ }
+ lastneeded = needed;
+
+ lifconf.lifc_family = af;
+ lifconf.lifc_flags = LIFC_NOXMIT;
+ lifconf.lifc_len = needed;
+ lifconf.lifc_buf = buf;
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ flog_err(LIB_ERR_PRIVILEGES, "Can't raise privileges");
+
+ ret = ioctl(sock, SIOCGLIFCONF, &lifconf);
+
+ if (ret < 0) {
+ if (errno == EINVAL)
+ goto calculate_lifc_len; /* deliberately hold privileges
+ */
+
+ zlog_warn("SIOCGLIFCONF: %s", safe_strerror(errno));
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ flog_err(LIB_ERR_PRIVILEGES, "Can't lower privileges");
+
+ goto end;
+ }
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ flog_err(LIB_ERR_PRIVILEGES, "Can't lower privileges");
+
+ /* Allocate interface. */
+ lifreq = lifconf.lifc_req;
+
+ for (n = 0; n < lifconf.lifc_len; n += sizeof(struct lifreq)) {
+ /* we treat Solaris logical interfaces as addresses, because
+ * that is
+ * how PF_ROUTE on Solaris treats them. Hence we can not
+ * directly use
+ * the lifreq_name to get the ifp. We need to normalise the
+ * name
+ * before attempting get.
+ *
+ * Solaris logical interface names are in the form of:
+ * <interface name>:<logical interface id>
+ */
+ unsigned int normallen = 0;
+ uint64_t lifflags;
+
+ /* We should exclude ~IFF_UP interfaces, as we'll find out about
+ * them
+ * coming up later through RTM_NEWADDR message on the route
+ * socket.
+ */
+ if (if_get_flags_direct(lifreq->lifr_name, &lifflags,
+ lifreq->lifr_addr.ss_family)
+ || !CHECK_FLAG(lifflags, IFF_UP)) {
+ lifreq++;
+ continue;
+ }
+
+ /* Find the normalised name */
+ while ((normallen < sizeof(lifreq->lifr_name))
+ && (*(lifreq->lifr_name + normallen) != '\0')
+ && (*(lifreq->lifr_name + normallen) != ':'))
+ normallen++;
+
+ ifp = if_get_by_name(lifreq->lifr_name, VRF_DEFAULT, 0);
+
+ if (lifreq->lifr_addr.ss_family == AF_INET)
+ ifp->flags |= IFF_IPV4;
+
+ if (lifreq->lifr_addr.ss_family == AF_INET6) {
+ ifp->flags |= IFF_IPV6;
+ }
+
+ if_add_update(ifp);
+
+ interface_info_ioctl(ifp);
+
+ /* If a logical interface pass the full name so it can be
+ * as a label on the address
+ */
+ if (*(lifreq->lifr_name + normallen) != '\0')
+ if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
+ lifreq->lifr_name);
+ else
+ if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
+ NULL);
+
+ /* Poke the interface flags. Lets IFF_UP mangling kick in */
+ if_flags_update(ifp, ifp->flags);
+
+ lifreq++;
+ }
end:
- close (sock);
- XFREE (MTYPE_TMP, lifconf.lifc_buf);
- return ret;
+ close(sock);
+ XFREE(MTYPE_TMP, lifconf.lifc_buf);
+ return ret;
}
/* Get interface's index by ioctl. */
-static int
-if_get_index (struct interface *ifp)
+static int if_get_index(struct interface *ifp)
{
- int ret;
- struct lifreq lifreq;
+ int ret;
+ struct lifreq lifreq;
- lifreq_set_name (&lifreq, ifp->name);
+ lifreq_set_name(&lifreq, ifp->name);
- if (ifp->flags & IFF_IPV4)
- ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq);
- else if (ifp->flags & IFF_IPV6)
- ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq);
- else
- ret = -1;
+ if (ifp->flags & IFF_IPV4)
+ ret = AF_IOCTL(AF_INET, SIOCGLIFINDEX, (caddr_t)&lifreq);
+ else if (ifp->flags & IFF_IPV6)
+ ret = AF_IOCTL(AF_INET6, SIOCGLIFINDEX, (caddr_t)&lifreq);
+ else
+ ret = -1;
- if (ret < 0)
- {
- zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name);
- return ret;
- }
+ if (ret < 0) {
+ zlog_warn("SIOCGLIFINDEX(%s) failed", ifp->name);
+ return ret;
+ }
- /* OK we got interface index. */
+/* OK we got interface index. */
#ifdef ifr_ifindex
- ifp->ifindex = lifreq.lifr_ifindex;
+ if_set_index(ifp, lifreq.lifr_ifindex);
#else
- ifp->ifindex = lifreq.lifr_index;
+ if_set_index(ifp, lifreq.lifr_index);
#endif
- return ifp->ifindex;
-
+ return ifp->ifindex;
}
/* Interface address lookup by ioctl. This function only looks up
IPv4 address. */
-#define ADDRLEN(sa) (((sa)->sa_family == AF_INET ? \
- sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)))
+#define ADDRLEN(sa) \
+ (((sa)->sa_family == AF_INET ? sizeof(struct sockaddr_in) \
+ : sizeof(struct sockaddr_in6)))
#define SIN(s) ((struct sockaddr_in *)(s))
#define SIN6(s) ((struct sockaddr_in6 *)(s))
/* Retrieve address information for the given ifp */
-static int
-if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label)
+static int if_get_addr(struct interface *ifp, struct sockaddr *addr,
+ const char *label)
{
- int ret;
- struct lifreq lifreq;
- struct sockaddr_storage mask, dest;
- char *dest_pnt = NULL;
- u_char prefixlen = 0;
- afi_t af;
- int flags = 0;
-
- /* Interface's name and address family.
- * We need to use the logical interface name / label, if we've been
- * given one, in order to get the right address
- */
- strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ);
-
- /* Interface's address. */
- memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr));
- af = addr->sa_family;
-
- /* Point to point or broad cast address pointer init. */
- dest_pnt = NULL;
-
- if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0)
- {
- memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr));
- if (af == AF_INET)
- dest_pnt = (char *) &(SIN (&dest)->sin_addr);
- else
- dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr);
- flags = ZEBRA_IFA_PEER;
- }
-
- if (af == AF_INET)
- {
- ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq);
-
- if (ret < 0)
- {
- if (errno != EADDRNOTAVAIL)
- {
- zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name,
- safe_strerror (errno));
- return ret;
- }
- return 0;
- }
- memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr));
-
- prefixlen = ip_masklen (SIN (&mask)->sin_addr);
- if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0))
- {
- memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in));
- dest_pnt = (char *) &SIN (&dest)->sin_addr;
- }
- }
- else if (af == AF_INET6)
- {
- if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0)
- {
- if (ifp->flags & IFF_POINTOPOINT)
- prefixlen = IPV6_MAX_BITLEN;
- else
- zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s",
- ifp->name, safe_strerror (errno));
+ int ret;
+ struct lifreq lifreq;
+ struct sockaddr_storage mask, dest;
+ char *dest_pnt = NULL;
+ uint8_t prefixlen = 0;
+ afi_t af;
+ int flags = 0;
+
+ /* Interface's name and address family.
+ * We need to use the logical interface name / label, if we've been
+ * given one, in order to get the right address
+ */
+ strncpy(lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ);
+
+ /* Interface's address. */
+ memcpy(&lifreq.lifr_addr, addr, ADDRLEN(addr));
+ af = addr->sa_family;
+
+ /* Point to point or broad cast address pointer init. */
+ dest_pnt = NULL;
+
+ if (AF_IOCTL(af, SIOCGLIFDSTADDR, (caddr_t)&lifreq) >= 0) {
+ memcpy(&dest, &lifreq.lifr_dstaddr, ADDRLEN(addr));
+ if (af == AF_INET)
+ dest_pnt = (char *)&(SIN(&dest)->sin_addr);
+ else
+ dest_pnt = (char *)&(SIN6(&dest)->sin6_addr);
+ flags = ZEBRA_IFA_PEER;
}
- else
- {
- prefixlen = lifreq.lifr_addrlen;
+
+ if (af == AF_INET) {
+ ret = if_ioctl(SIOCGLIFNETMASK, (caddr_t)&lifreq);
+
+ if (ret < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ zlog_warn("SIOCGLIFNETMASK (%s) fail: %s",
+ ifp->name, safe_strerror(errno));
+ return ret;
+ }
+ return 0;
+ }
+ memcpy(&mask, &lifreq.lifr_addr, ADDRLEN(addr));
+
+ prefixlen = ip_masklen(SIN(&mask)->sin_addr);
+ if (!dest_pnt
+ && (if_ioctl(SIOCGLIFBRDADDR, (caddr_t)&lifreq) >= 0)) {
+ memcpy(&dest, &lifreq.lifr_broadaddr,
+ sizeof(struct sockaddr_in));
+ dest_pnt = (char *)&SIN(&dest)->sin_addr;
+ }
+ } else if (af == AF_INET6) {
+ if (if_ioctl_ipv6(SIOCGLIFSUBNET, (caddr_t)&lifreq) < 0) {
+ if (ifp->flags & IFF_POINTOPOINT)
+ prefixlen = IPV6_MAX_BITLEN;
+ else
+ zlog_warn("SIOCGLIFSUBNET (%s) fail: %s",
+ ifp->name, safe_strerror(errno));
+ } else {
+ prefixlen = lifreq.lifr_addrlen;
+ }
}
- }
- /* Set address to the interface. */
- if (af == AF_INET)
- connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen,
- (struct in_addr *) dest_pnt, label);
- else if (af == AF_INET6)
- connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen,
- (struct in6_addr *) dest_pnt, label);
+ /* Set address to the interface. */
+ if (af == AF_INET)
+ connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen,
+ (struct in_addr *)dest_pnt, label);
+ else if (af == AF_INET6)
+ connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL,
+ prefixlen, label);
- return 0;
+ return 0;
}
/* Fetch interface information via ioctl(). */
-static void
-interface_info_ioctl (struct interface *ifp)
+static void interface_info_ioctl(struct interface *ifp)
{
- if_get_index (ifp);
- if_get_flags (ifp);
- if_get_mtu (ifp);
- if_get_metric (ifp);
+ if_get_index(ifp);
+ if_get_flags(ifp);
+ if_get_mtu(ifp);
+ if_get_metric(ifp);
}
/* Lookup all interface information. */
-void
-interface_list (struct zebra_ns *zns)
+void interface_list(struct zebra_ns *zns)
{
- if (zns->ns_id != NS_DEFAULT)
- {
- zlog_warn ("interface_list: ignore NS %u", zns->ns_id);
- return;
- }
- interface_list_ioctl (AF_INET);
- interface_list_ioctl (AF_INET6);
- interface_list_ioctl (AF_UNSPEC);
+ if (zns->ns_id != NS_DEFAULT) {
+ zlog_warn("interface_list: ignore NS %u", zns->ns_id);
+ return;
+ }
+ interface_list_ioctl(AF_INET);
+ interface_list_ioctl(AF_INET6);
+ interface_list_ioctl(AF_UNSPEC);
}
-struct connected *
-if_lookup_linklocal (struct interface *ifp)
+struct connected *if_lookup_linklocal(struct interface *ifp)
{
- struct listnode *node;
- struct connected *ifc;
+ struct listnode *node;
+ struct connected *ifc;
- if (ifp == NULL)
- return NULL;
+ if (ifp == NULL)
+ return NULL;
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
- {
- if ((ifc->address->family == AF_INET6) &&
- (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6)))
- return ifc;
- }
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+ if ((ifc->address->family == AF_INET6)
+ && (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)))
+ return ifc;
+ }
- return NULL;
+ return NULL;
}
+
+#endif /* SUNOS_5 */