summaryrefslogtreecommitdiff
path: root/zebra/if_ioctl_solaris.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/if_ioctl_solaris.c')
-rw-r--r--zebra/if_ioctl_solaris.c50
1 files changed, 38 insertions, 12 deletions
diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c
index efa65060..898c1610 100644
--- a/zebra/if_ioctl_solaris.c
+++ b/zebra/if_ioctl_solaris.c
@@ -34,7 +34,7 @@
#include "zebra/interface.h"
void lifreq_set_name (struct lifreq *, struct interface *);
-static int if_get_addr (struct interface *, struct sockaddr *);
+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;
@@ -71,7 +71,7 @@ interface_list_ioctl (int af)
calculate_lifc_len: /* must hold privileges to enter here */
lifn.lifn_family = af;
- lifn.lifn_flags = 0;
+ lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
ret = ioctl (sock, SIOCGLIFNUM, &lifn);
save_errno = errno;
@@ -108,7 +108,7 @@ calculate_lifc_len: /* must hold privileges to enter here */
lastneeded = needed;
lifconf.lifc_family = af;
- lifconf.lifc_flags = 0;
+ lifconf.lifc_flags = LIFC_NOXMIT;
lifconf.lifc_len = needed;
lifconf.lifc_buf = buf;
@@ -138,9 +138,22 @@ calculate_lifc_len: /* must hold privileges to enter here */
for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq))
{
- ifp = if_get_by_name_len(lifreq->lifr_name,
- strnlen(lifreq->lifr_name,
- sizeof(lifreq->lifr_name)));
+ /* 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;
+
+ 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);
if (lifreq->lifr_addr.ss_family == AF_INET)
ifp->flags |= IFF_IPV4;
@@ -158,7 +171,15 @@ calculate_lifc_len: /* must hold privileges to enter here */
if_add_update (ifp);
interface_info_ioctl (ifp);
- if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr);
+
+ /* 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);
lifreq++;
}
@@ -209,8 +230,9 @@ if_get_index (struct interface *ifp)
#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)
+if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label)
{
int ret;
struct lifreq lifreq;
@@ -219,8 +241,11 @@ if_get_addr (struct interface *ifp, struct sockaddr *addr)
u_char prefixlen = 0;
afi_t af;
- /* Interface's name and address family. */
- strncpy (lifreq.lifr_name, ifp->name, IFNAMSIZ);
+ /* 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));
@@ -306,11 +331,11 @@ if_get_addr (struct interface *ifp, struct sockaddr *addr)
/* 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);
+ (struct in_addr *) dest_pnt, label);
#ifdef HAVE_IPV6
else if (af == AF_INET6)
connected_add_ipv6 (ifp, &SIN6 (addr)->sin6_addr, prefixlen,
- (struct in6_addr *) dest_pnt);
+ (struct in6_addr *) dest_pnt, label);
#endif /* HAVE_IPV6 */
return 0;
@@ -332,6 +357,7 @@ interface_list ()
{
interface_list_ioctl (AF_INET);
interface_list_ioctl (AF_INET6);
+ interface_list_ioctl (AF_UNSPEC);
}
struct connected *