2
* Interface looking up by ioctl () on Solaris.
3
* Copyright (C) 1997, 98 Kunihiro Ishiguro
5
* This file is part of GNU Zebra.
7
* GNU Zebra is free software; you can redistribute it and/or modify it
8
* under the terms of the GNU General Public License as published by the
9
* Free Software Foundation; either version 2, or (at your option) any
12
* GNU Zebra is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with GNU Zebra; see the file COPYING. If not, write to the Free
19
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26
#include "sockunion.h"
29
#include "connected.h"
34
#include "zebra/interface.h"
36
void lifreq_set_name (struct lifreq *, struct interface *);
37
static int if_get_addr (struct interface *, struct sockaddr *);
38
static void interface_info_ioctl (struct interface *);
39
extern struct zebra_privs_t zserv_privs;
42
interface_list_ioctl (int af)
49
struct lifreq *lifreq;
50
struct lifconf lifconf;
51
struct interface *ifp;
54
size_t needed, lastneeded = 0;
57
if (zserv_privs.change(ZPRIVS_RAISE))
58
zlog (NULL, LOG_ERR, "Can't raise privileges");
60
sock = socket (af, SOCK_DGRAM, 0);
63
zlog_warn ("Can't make %s socket stream: %s",
64
(af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno));
66
if (zserv_privs.change(ZPRIVS_LOWER))
67
zlog (NULL, LOG_ERR, "Can't lower privileges");
72
calculate_lifc_len: /* must hold privileges to enter here */
73
lifn.lifn_family = af;
75
ret = ioctl (sock, SIOCGLIFNUM, &lifn);
78
if (zserv_privs.change(ZPRIVS_LOWER))
79
zlog (NULL, LOG_ERR, "Can't lower privileges");
83
zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s",
84
safe_strerror (save_errno));
88
ifnum = lifn.lifn_count;
91
* When calculating the buffer size needed, add a small number
92
* of interfaces to those we counted. We do this to capture
93
* the interface status of potential interfaces which may have
94
* been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
96
needed = (ifnum + 4) * sizeof (struct lifreq);
97
if (needed > lastneeded || needed < lastneeded / 2)
100
XFREE (MTYPE_TMP, buf);
101
if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL)
103
zlog_warn ("interface_list_ioctl: malloc failed");
110
lifconf.lifc_family = af;
111
lifconf.lifc_flags = 0;
112
lifconf.lifc_len = needed;
113
lifconf.lifc_buf = buf;
115
if (zserv_privs.change(ZPRIVS_RAISE))
116
zlog (NULL, LOG_ERR, "Can't raise privileges");
118
ret = ioctl (sock, SIOCGLIFCONF, &lifconf);
123
goto calculate_lifc_len; /* deliberately hold privileges */
125
zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno));
127
if (zserv_privs.change(ZPRIVS_LOWER))
128
zlog (NULL, LOG_ERR, "Can't lower privileges");
133
if (zserv_privs.change(ZPRIVS_LOWER))
134
zlog (NULL, LOG_ERR, "Can't lower privileges");
136
/* Allocate interface. */
137
lifreq = lifconf.lifc_req;
139
for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq))
141
ifp = if_get_by_name_len(lifreq->lifr_name,
142
strnlen(lifreq->lifr_name,
143
sizeof(lifreq->lifr_name)));
145
if (lifreq->lifr_addr.ss_family == AF_INET)
146
ifp->flags |= IFF_IPV4;
148
if (lifreq->lifr_addr.ss_family == AF_INET6)
151
ifp->flags |= IFF_IPV6;
155
#endif /* HAVE_IPV6 */
160
interface_info_ioctl (ifp);
161
if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr);
167
XFREE (MTYPE_TMP, lifconf.lifc_buf);
171
/* Get interface's index by ioctl. */
173
if_get_index (struct interface *ifp)
176
struct lifreq lifreq;
178
lifreq_set_name (&lifreq, ifp);
180
if (ifp->flags & IFF_IPV4)
181
ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq);
182
else if (ifp->flags & IFF_IPV6)
183
ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq);
189
zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name);
193
/* OK we got interface index. */
195
ifp->ifindex = lifreq.lifr_ifindex;
197
ifp->ifindex = lifreq.lifr_index;
204
/* Interface address lookup by ioctl. This function only looks up
206
#define ADDRLEN(sa) (((sa)->sa_family == AF_INET ? \
207
sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)))
209
#define SIN(s) ((struct sockaddr_in *)(s))
210
#define SIN6(s) ((struct sockaddr_in6 *)(s))
213
if_get_addr (struct interface *ifp, struct sockaddr *addr)
216
struct lifreq lifreq;
217
struct sockaddr_storage mask, dest;
218
char *dest_pnt = NULL;
219
u_char prefixlen = 0;
222
/* Interface's name and address family. */
223
strncpy (lifreq.lifr_name, ifp->name, IFNAMSIZ);
225
/* Interface's address. */
226
memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr));
227
af = addr->sa_family;
229
/* Point to point or broad cast address pointer init. */
232
if (ifp->flags & IFF_POINTOPOINT)
234
ret = AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq);
238
zlog_warn ("SIOCGLIFDSTADDR (%s) fail: %s",
239
ifp->name, safe_strerror (errno));
242
memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr));
244
dest_pnt = (char *) &(SIN (&dest)->sin_addr);
246
dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr);
251
ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq);
255
if (errno != EADDRNOTAVAIL)
257
zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name,
258
safe_strerror (errno));
263
memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr));
265
prefixlen = ip_masklen (SIN (&mask)->sin_addr);
266
if (ifp->flags & IFF_BROADCAST)
268
ret = if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq);
271
if (errno != EADDRNOTAVAIL)
273
zlog_warn ("SIOCGLIFBRDADDR (%s) fail: %s",
274
ifp->name, safe_strerror (errno));
279
memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in));
280
dest_pnt = (char *) &SIN (&dest)->sin_addr;
284
else if (af == AF_INET6)
286
if (ifp->flags & IFF_POINTOPOINT)
288
prefixlen = IPV6_MAX_BITLEN;
292
ret = if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq);
295
zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s",
296
ifp->name, safe_strerror (errno));
300
prefixlen = lifreq.lifr_addrlen;
304
#endif /* HAVE_IPV6 */
306
/* Set address to the interface. */
308
connected_add_ipv4 (ifp, 0, &SIN (addr)->sin_addr, prefixlen,
309
(struct in_addr *) dest_pnt, NULL);
311
else if (af == AF_INET6)
312
connected_add_ipv6 (ifp, &SIN6 (addr)->sin6_addr, prefixlen,
313
(struct in6_addr *) dest_pnt);
314
#endif /* HAVE_IPV6 */
319
/* Fetch interface information via ioctl(). */
321
interface_info_ioctl (struct interface *ifp)
329
/* Lookup all interface information. */
333
interface_list_ioctl (AF_INET);
334
interface_list_ioctl (AF_INET6);
338
if_lookup_linklocal (struct interface *ifp)
341
struct listnode *node;
342
struct connected *ifc;
347
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
349
if ((ifc->address->family == AF_INET6) &&
350
(IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6)))
353
#endif /* HAVE_IPV6 */