diff options
author | paul <paul> | 2004-05-09 18:21:35 +0000 |
---|---|---|
committer | paul <paul> | 2004-05-09 18:21:35 +0000 |
commit | 8842468c7a1c13c9dde1e26714eb2b2c56ec053b (patch) | |
tree | 565aba9dd8a4caf29ea72494c7fdeb3e63be6fe3 /zebra/ioctl_solaris.c | |
parent | 66e9488cae034947e9e22e78cfee3e587573b3f3 (diff) |
2004-05-09 Paul Jakma <paul@dishone.st>
* if_ioctl_solaris.c: Add zprivs support.
* ioctl_solaris.c: ditto.
2004-05-09 Sowmini Varadhan <sowmini.varadhan@sun.com>
* if_ioctl_solaris.c: New file, Solaris interface ioctl methods.
* ioctl_solaris.c: New file, Common solaris ioctl methods.
Diffstat (limited to 'zebra/ioctl_solaris.c')
-rw-r--r-- | zebra/ioctl_solaris.c | 421 |
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 */ |