diff options
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/ChangeLog | 6 | ||||
-rw-r--r-- | zebra/if_ioctl_solaris.c | 348 | ||||
-rw-r--r-- | zebra/ioctl_solaris.c | 421 |
3 files changed, 774 insertions, 1 deletions
diff --git a/zebra/ChangeLog b/zebra/ChangeLog index 8920b961..053f9e87 100644 --- a/zebra/ChangeLog +++ b/zebra/ChangeLog @@ -12,6 +12,8 @@ * rt_netlink.c: (netlink_interface) set mtu6 to mtu (netlink_link_change) ditto * ipforward_solaris.c: fix typo of ND variable. + * if_ioctl_solaris.c: Add zprivs support. + * ioctl_solaris.c: ditto. 2004-05-09 Sowmini Varadhan <sowmini.varadhan@sun.com> @@ -30,7 +32,9 @@ and RTM_IFANNOUNCE. (if_flag_dump_vty) Solaris IFF_IPV4 and IFF_IPV6 if flags (if_dump_vty) print mtu6 if not same as mtu - + * if_ioctl_solaris.c: New file, Solaris interface ioctl methods. + * ioctl_solaris.c: New file, Common solaris ioctl methods. + 2004-04-06 Krzysztof Oledzki <oleq@ans.pl> * rt_netlink.c: Do not ignore metric when reading kernel routing diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c new file mode 100644 index 00000000..b07580c2 --- /dev/null +++ b/zebra/if_ioctl_solaris.c @@ -0,0 +1,348 @@ +/* + * Interface looking up by ioctl () on 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 "if.h" +#include "sockunion.h" +#include "prefix.h" +#include "ioctl.h" +#include "connected.h" +#include "memory.h" +#include "log.h" + +#include "zebra/interface.h" + +void lifreq_set_name (struct lifreq *, struct interface *); +static int if_get_addr (struct interface *, struct sockaddr *); +static void interface_info_ioctl (struct interface *); + + +int +interface_list_ioctl (int af) +{ + int ret; + int sock; +#define IFNUM_BASE 32 + struct lifnum lifn; + int ifnum; + struct lifreq *lifreq; + struct lifconf lifconf; + struct interface *ifp; + int n; + size_t needed, lastneeded = 0; + char *buf = NULL; + + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_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"), strerror (errno)); + + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + return -1; + } + +calculate_lifc_len: /* must hold privileges to enter here */ + lifn.lifn_family = af; + lifn.lifn_flags = 0; + ret = ioctl (sock, SIOCGLIFNUM, &lifn); + + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + if (ret < 0) + { + zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s", + strerror (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 = 0; + lifconf.lifc_len = needed; + lifconf.lifc_buf = buf; + + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_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", strerror (errno)); + + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + goto end; + } + + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + /* Allocate interface. */ + lifreq = lifconf.lifc_req; + + for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq)) + { + ifp = if_get_by_name (lifreq->lifr_name); + 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_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr); + lifreq++; + } + +end: + close (sock); + XFREE (MTYPE_TMP, lifconf.lifc_buf); + return ret; +} + +/* Get interface's index by ioctl. */ +int +if_get_index (struct interface *ifp) +{ + int ret; + struct lifreq lifreq; + + 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, SIOCGLIFINDEX, (caddr_t) & lifreq); + else if (ifp->flags & IFF_IPV6) + ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq); + else + ret = -1; + + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + if (ret < 0) + { + zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name); + return ret; + } + + /* OK we got interface index. */ +#ifdef ifr_ifindex + ifp->ifindex = lifreq.lifr_ifindex; +#else + ifp->ifindex = lifreq.lifr_index; +#endif + 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 SIN(s) ((struct sockaddr_in *)(s)) +#define SIN6(s) ((struct sockaddr_in6 *)(s)) + +static int +if_get_addr (struct interface *ifp, struct sockaddr *addr) +{ + int ret; + struct lifreq lifreq; + struct sockaddr_storage mask, dest; + char *dest_pnt = NULL; + u_char prefixlen = 0; + afi_t af; + + /* Interface's name and address family. */ + strncpy (lifreq.lifr_name, 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 (ifp->flags & IFF_POINTOPOINT) + { + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + + ret = AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq); + + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + if (ret < 0) + { + zlog_warn ("SIOCGLIFDSTADDR (%s) fail: %s", + ifp->name, strerror (errno)); + return ret; + } + 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); + } + + 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, + strerror (errno)); + return ret; + } + return 0; + } + memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr)); + + prefixlen = ip_masklen (SIN (&mask)->sin_addr); + if (ifp->flags & IFF_BROADCAST) + { + ret = if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq); + if (ret < 0) + { + if (errno != EADDRNOTAVAIL) + { + zlog_warn ("SIOCGLIFBRDADDR (%s) fail: %s", + ifp->name, strerror (errno)); + return ret; + } + return 0; + } + memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in)); + dest_pnt = (char *) &SIN (&dest)->sin_addr; + } + } + else + { + if (ifp->flags & IFF_POINTOPOINT) + { + prefixlen = IPV6_MAX_BITLEN; + } + else + { + ret = if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq); + if (ret < 0) + { + zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s", + ifp->name, strerror (errno)); + } + else + { + prefixlen = lifreq.lifr_addrlen; + } + } + } + + + /* Set address to the interface. */ + if (af == AF_INET) + connected_add_ipv4 (ifp, 0, &SIN (addr)->sin_addr, prefixlen, + (struct in_addr *) dest_pnt, NULL); + else + connected_add_ipv6 (ifp, &SIN6 (addr)->sin6_addr, prefixlen, + (struct in6_addr *) dest_pnt); + + return 0; +} + +/* Fetch interface information via ioctl(). */ +static void +interface_info_ioctl (struct interface *ifp) +{ + if_get_index (ifp); + if_get_flags (ifp); + if_get_mtu (ifp); + if_get_metric (ifp); +} + +/* Lookup all interface information. */ +void +interface_list () +{ + interface_list_ioctl (AF_INET); + interface_list_ioctl (AF_INET6); +} + +struct connected * +if_lookup_linklocal (struct interface *ifp) +{ + listnode node; + struct connected *ifc; + + if (ifp == NULL) + return NULL; + + for (node = listhead (ifp->connected); node; node = nextnode (node)) + { + ifc = getdata (node); + + if ((ifc->address->family == AF_INET6) && + (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6))) + return ifc; + } + return NULL; +} 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 */ |