summaryrefslogtreecommitdiff
path: root/zebra/ioctl_solaris.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/ioctl_solaris.c')
-rw-r--r--zebra/ioctl_solaris.c421
1 files changed, 421 insertions, 0 deletions
diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c
new file mode 100644
index 00000000..2fdffc61
--- /dev/null
+++ b/zebra/ioctl_solaris.c
@@ -0,0 +1,421 @@
+/*
+ * Common ioctl functions for Solaris.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "prefix.h"
+#include "ioctl.h"
+#include "log.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+
+
+/* clear and set interface name string */
+void
+lifreq_set_name (struct lifreq *lifreq, struct interface *ifp)
+{
+ strncpy (lifreq->lifr_name, ifp->name, IFNAMSIZ);
+}
+
+/* call ioctl system call */
+int
+if_ioctl (u_long request, caddr_t buffer)
+{
+ int sock;
+ int ret = 0;
+ int err = 0;
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog (NULL, LOG_ERR, "Can't raise privileges");
+
+ sock = socket (AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+ perror ("socket");
+ exit (1);
+ }
+
+ ret = ioctl (sock, request, buffer);
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+
+ if (ret < 0)
+ {
+ err = errno;
+ }
+ close (sock);
+
+ if (ret < 0)
+ {
+ errno = err;
+ return ret;
+ }
+ return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+if_ioctl_ipv6 (u_long request, caddr_t buffer)
+{
+ int sock;
+ int ret = 0;
+ int err = 0;
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog (NULL, LOG_ERR, "Can't raise privileges");
+
+ sock = socket (AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+ perror ("socket");
+ exit (1);
+ }
+
+ ret = ioctl (sock, request, buffer);
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+
+ if (ret < 0)
+ {
+ err = errno;
+ }
+ close (sock);
+
+ if (ret < 0)
+ {
+ errno = err;
+ return ret;
+ }
+ return 0;
+}
+#endif /* HAVE_IPV6 */
+
+/*
+ * get interface metric
+ * -- if value is not avaliable set -1
+ */
+void
+if_get_metric (struct interface *ifp)
+{
+ struct lifreq lifreq;
+ int ret;
+
+ lifreq_set_name (&lifreq, ifp);
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog (NULL, LOG_ERR, "Can't raise privileges");
+
+ if (ifp->flags & IFF_IPV4)
+ ret = AF_IOCTL (AF_INET, SIOCGLIFMETRIC, (caddr_t) & lifreq);
+ else if (ifp->flags & IFF_IPV6)
+ ret = AF_IOCTL (AF_INET6, SIOCGLIFMETRIC, (caddr_t) & lifreq);
+ else
+ ret = -1;
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+
+ if (ret < 0)
+ return;
+
+ ifp->metric = lifreq.lifr_metric;
+
+ if (ifp->metric == 0)
+ ifp->metric = 1;
+}
+
+/* get interface MTU */
+void
+if_get_mtu (struct interface *ifp)
+{
+ struct lifreq lifreq;
+ int ret;
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog (NULL, LOG_ERR, "Can't raise privileges");
+
+ if (ifp->flags & IFF_IPV4)
+ {
+ lifreq_set_name (&lifreq, ifp);
+ ret = AF_IOCTL (AF_INET, SIOCGLIFMTU, (caddr_t) & lifreq);
+ if (ret < 0)
+ {
+ zlog_info ("Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)",
+ ifp->name);
+ ifp->mtu = -1;
+ }
+ else
+ {
+ ifp->mtu = lifreq.lifr_metric;
+ }
+ }
+
+
+ if ((ifp->flags & IFF_IPV6) == 0)
+ goto out;
+
+ lifreq_set_name (&lifreq, ifp);
+ ret = AF_IOCTL (AF_INET6, SIOCGLIFMTU, (caddr_t) & lifreq);
+ if (ret < 0)
+ {
+ zlog_info ("Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)", ifp->name);
+ ifp->mtu6 = -1;
+ }
+ else
+ {
+ ifp->mtu6 = lifreq.lifr_metric;
+ }
+
+out:
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+}
+
+/* Set up interface's address, netmask (and broadcast? ).
+ Solaris uses ifname:number semantics to set IP address aliases. */
+int
+if_set_prefix (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct ifreq ifreq;
+ struct sockaddr_in addr;
+ struct sockaddr_in broad;
+ struct sockaddr_in mask;
+ struct prefix_ipv4 ifaddr;
+ struct prefix_ipv4 *p;
+
+ p = (struct prefix_ipv4 *) ifc->address;
+
+ ifaddr = *p;
+
+ strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
+
+ addr.sin_addr = p->prefix;
+ addr.sin_family = p->family;
+ memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
+
+ ret = if_ioctl (SIOCSIFADDR, (caddr_t) & ifreq);
+
+ if (ret < 0)
+ return ret;
+
+ /* We need mask for make broadcast addr. */
+ masklen2ip (p->prefixlen, &mask.sin_addr);
+
+ if (if_is_broadcast (ifp))
+ {
+ apply_mask_ipv4 (&ifaddr);
+ addr.sin_addr = ifaddr.prefix;
+
+ broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
+ broad.sin_family = p->family;
+
+ memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in));
+ ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) & ifreq);
+ if (ret < 0)
+ goto out;
+ }
+
+ mask.sin_family = p->family;
+#ifdef SUNOS_5
+ memcpy (&mask, &ifreq.ifr_addr, sizeof (mask));
+#else
+ memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in));
+#endif /* SUNOS5 */
+ ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) & ifreq);
+
+ return ((ret < 0) ? ret : 0);
+}
+
+/* Set up interface's address, netmask (and broadcast).
+ Solaris uses ifname:number semantics to set IP address aliases. */
+int
+if_unset_prefix (struct interface *ifp, struct connected *ifc)
+{
+ int ret;
+ struct ifreq ifreq;
+ struct sockaddr_in addr;
+ struct prefix_ipv4 *p;
+
+ p = (struct prefix_ipv4 *) ifc->address;
+
+ strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
+
+ memset (&addr, 0, sizeof (struct sockaddr_in));
+ addr.sin_family = p->family;
+ memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
+
+ ret = if_ioctl (SIOCSIFADDR, (caddr_t) & ifreq);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* get interface flags */
+void
+if_get_flags (struct interface *ifp)
+{
+ int ret;
+ struct lifreq lifreq;
+ unsigned long flags4 = 0, flags6 = 0;
+
+ if (ifp->flags & IFF_IPV4)
+ {
+ lifreq_set_name (&lifreq, ifp);
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog (NULL, LOG_ERR, "Can't raise privileges");
+
+ ret = AF_IOCTL (AF_INET, SIOCGLIFFLAGS, (caddr_t) & lifreq);
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+
+ flags4 = (lifreq.lifr_flags & 0xffffffff);
+ if (!(flags4 & IFF_UP))
+ flags4 &= ~IFF_IPV4;
+ }
+
+ if (ifp->flags & IFF_IPV6)
+ {
+ lifreq_set_name (&lifreq, ifp);
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog (NULL, LOG_ERR, "Can't raise privileges");
+
+ ret = AF_IOCTL (AF_INET6, SIOCGLIFFLAGS, (caddr_t) & lifreq);
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+
+ flags6 = (lifreq.lifr_flags & 0xffffffff);
+ if (!(flags6 & IFF_UP))
+ flags6 &= ~IFF_IPV6;
+ }
+
+ ifp->flags = (flags4 | flags6);
+}
+
+/* Set interface flags */
+int
+if_set_flags (struct interface *ifp, unsigned long flags)
+{
+ int ret;
+ struct lifreq lifreq;
+
+ lifreq_set_name (&lifreq, ifp);
+
+ lifreq.lifr_flags = ifp->flags;
+ lifreq.lifr_flags |= flags;
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog (NULL, LOG_ERR, "Can't raise privileges");
+
+ if (ifp->flags & IFF_IPV4)
+ ret = AF_IOCTL (AF_INET, SIOCSLIFFLAGS, (caddr_t) & lifreq);
+ else if (ifp->flags & IFF_IPV6)
+ ret = AF_IOCTL (AF_INET6, SIOCSLIFFLAGS, (caddr_t) & lifreq);
+ else
+ ret = -1;
+
+ if (ret < 0)
+ zlog_info ("can't set interface flags on %s: %s", ifp->name,
+ strerror (errno));
+ else
+ ret = 0;
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+}
+
+/* Unset interface's flag. */
+int
+if_unset_flags (struct interface *ifp, unsigned long flags)
+{
+ int ret;
+ struct lifreq lifreq;
+
+ lifreq_set_name (&lifreq, ifp);
+
+ lifreq.lifr_flags = ifp->flags;
+ lifreq.lifr_flags &= ~flags;
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog (NULL, LOG_ERR, "Can't raise privileges");
+
+ if (ifp->flags & IFF_IPV4)
+ ret = AF_IOCTL (AF_INET, SIOCSLIFFLAGS, (caddr_t) & lifreq);
+ else if (ifp->flags & IFF_IPV6)
+ ret = AF_IOCTL (AF_INET6, SIOCSLIFFLAGS, (caddr_t) & lifreq);
+ else
+ ret = -1;
+
+ if (ret < 0)
+ zlog_info ("can't unset interface flags");
+ else
+ ret = 0;
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog (NULL, LOG_ERR, "Can't lower privileges");
+}
+
+#ifdef HAVE_IPV6
+
+/* Interface's address add/delete functions. */
+int
+if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ char addrbuf[INET_ADDRSTRLEN];
+
+ inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix),
+ addrbuf, sizeof (addrbuf));
+ zlog_warn ("Can't set %s on interface %s", addrbuf, ifp->name);
+
+ return 0;
+
+}
+
+int
+if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ char addrbuf[INET_ADDRSTRLEN];
+
+ inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix),
+ addrbuf, sizeof (addrbuf));
+ zlog_warn ("Can't delete %s on interface %s", addrbuf, ifp->name);
+
+ return 0;
+
+}
+
+#endif /* HAVE_IPV6 */