Annotation of embedaddon/quagga/zebra/if_ioctl_solaris.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Interface looking up by ioctl () on Solaris.
3: * Copyright (C) 1997, 98 Kunihiro Ishiguro
4: *
5: * This file is part of GNU Zebra.
6: *
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
10: * later version.
11: *
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.
16: *
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
20: * 02111-1307, USA.
21: */
22:
23: #include <zebra.h>
24:
25: #include "if.h"
26: #include "sockunion.h"
27: #include "prefix.h"
28: #include "ioctl.h"
29: #include "connected.h"
30: #include "memory.h"
31: #include "log.h"
32: #include "privs.h"
33:
34: #include "zebra/interface.h"
35:
36: void lifreq_set_name (struct lifreq *, const char *);
37: int if_get_flags_direct (const char *, uint64_t *, unsigned int af);
38: static int if_get_addr (struct interface *, struct sockaddr *, const char *);
39: static void interface_info_ioctl (struct interface *);
40: extern struct zebra_privs_t zserv_privs;
41:
42: int
43: interface_list_ioctl (int af)
44: {
45: int ret;
46: int sock;
47: #define IFNUM_BASE 32
48: struct lifnum lifn;
49: int ifnum;
50: struct lifreq *lifreq;
51: struct lifconf lifconf;
52: struct interface *ifp;
53: int n;
54: int save_errno;
55: size_t needed, lastneeded = 0;
56: char *buf = NULL;
57:
58: if (zserv_privs.change(ZPRIVS_RAISE))
59: zlog (NULL, LOG_ERR, "Can't raise privileges");
60:
61: sock = socket (af, SOCK_DGRAM, 0);
62: if (sock < 0)
63: {
64: zlog_warn ("Can't make %s socket stream: %s",
65: (af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno));
66:
67: if (zserv_privs.change(ZPRIVS_LOWER))
68: zlog (NULL, LOG_ERR, "Can't lower privileges");
69:
70: return -1;
71: }
72:
73: calculate_lifc_len: /* must hold privileges to enter here */
74: lifn.lifn_family = af;
75: lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
76: ret = ioctl (sock, SIOCGLIFNUM, &lifn);
77: save_errno = errno;
78:
79: if (zserv_privs.change(ZPRIVS_LOWER))
80: zlog (NULL, LOG_ERR, "Can't lower privileges");
81:
82: if (ret < 0)
83: {
84: zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s",
85: safe_strerror (save_errno));
86: close (sock);
87: return -1;
88: }
89: ifnum = lifn.lifn_count;
90:
91: /*
92: * When calculating the buffer size needed, add a small number
93: * of interfaces to those we counted. We do this to capture
94: * the interface status of potential interfaces which may have
95: * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
96: */
97: needed = (ifnum + 4) * sizeof (struct lifreq);
98: if (needed > lastneeded || needed < lastneeded / 2)
99: {
100: if (buf != NULL)
101: XFREE (MTYPE_TMP, buf);
102: if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL)
103: {
104: zlog_warn ("interface_list_ioctl: malloc failed");
105: close (sock);
106: return -1;
107: }
108: }
109: lastneeded = needed;
110:
111: lifconf.lifc_family = af;
112: lifconf.lifc_flags = LIFC_NOXMIT;
113: lifconf.lifc_len = needed;
114: lifconf.lifc_buf = buf;
115:
116: if (zserv_privs.change(ZPRIVS_RAISE))
117: zlog (NULL, LOG_ERR, "Can't raise privileges");
118:
119: ret = ioctl (sock, SIOCGLIFCONF, &lifconf);
120:
121: if (ret < 0)
122: {
123: if (errno == EINVAL)
124: goto calculate_lifc_len; /* deliberately hold privileges */
125:
126: zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno));
127:
128: if (zserv_privs.change(ZPRIVS_LOWER))
129: zlog (NULL, LOG_ERR, "Can't lower privileges");
130:
131: goto end;
132: }
133:
134: if (zserv_privs.change(ZPRIVS_LOWER))
135: zlog (NULL, LOG_ERR, "Can't lower privileges");
136:
137: /* Allocate interface. */
138: lifreq = lifconf.lifc_req;
139:
140: for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq))
141: {
142: /* we treat Solaris logical interfaces as addresses, because that is
143: * how PF_ROUTE on Solaris treats them. Hence we can not directly use
144: * the lifreq_name to get the ifp. We need to normalise the name
145: * before attempting get.
146: *
147: * Solaris logical interface names are in the form of:
148: * <interface name>:<logical interface id>
149: */
150: unsigned int normallen = 0;
151: uint64_t lifflags;
152:
153: /* We should exclude ~IFF_UP interfaces, as we'll find out about them
154: * coming up later through RTM_NEWADDR message on the route socket.
155: */
156: if (if_get_flags_direct (lifreq->lifr_name, &lifflags,
157: lifreq->lifr_addr.ss_family)
158: || !CHECK_FLAG (lifflags, IFF_UP))
159: {
160: lifreq++;
161: continue;
162: }
163:
164: /* Find the normalised name */
165: while ( (normallen < sizeof(lifreq->lifr_name))
166: && ( *(lifreq->lifr_name + normallen) != '\0')
167: && ( *(lifreq->lifr_name + normallen) != ':') )
168: normallen++;
169:
170: ifp = if_get_by_name_len(lifreq->lifr_name, normallen);
171:
172: if (lifreq->lifr_addr.ss_family == AF_INET)
173: ifp->flags |= IFF_IPV4;
174:
175: if (lifreq->lifr_addr.ss_family == AF_INET6)
176: {
177: #ifdef HAVE_IPV6
178: ifp->flags |= IFF_IPV6;
179: #else
180: lifreq++;
181: continue;
182: #endif /* HAVE_IPV6 */
183: }
184:
185: if_add_update (ifp);
186:
187: interface_info_ioctl (ifp);
188:
189: /* If a logical interface pass the full name so it can be
190: * as a label on the address
191: */
192: if ( *(lifreq->lifr_name + normallen) != '\0')
193: if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr,
194: lifreq->lifr_name);
195: else
196: if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL);
197:
198: /* Poke the interface flags. Lets IFF_UP mangling kick in */
199: if_flags_update (ifp, ifp->flags);
200:
201: lifreq++;
202: }
203:
204: end:
205: close (sock);
206: XFREE (MTYPE_TMP, lifconf.lifc_buf);
207: return ret;
208: }
209:
210: /* Get interface's index by ioctl. */
211: int
212: if_get_index (struct interface *ifp)
213: {
214: int ret;
215: struct lifreq lifreq;
216:
217: lifreq_set_name (&lifreq, ifp->name);
218:
219: if (ifp->flags & IFF_IPV4)
220: ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq);
221: else if (ifp->flags & IFF_IPV6)
222: ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq);
223: else
224: ret = -1;
225:
226: if (ret < 0)
227: {
228: zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name);
229: return ret;
230: }
231:
232: /* OK we got interface index. */
233: #ifdef ifr_ifindex
234: ifp->ifindex = lifreq.lifr_ifindex;
235: #else
236: ifp->ifindex = lifreq.lifr_index;
237: #endif
238: return ifp->ifindex;
239:
240: }
241:
242:
243: /* Interface address lookup by ioctl. This function only looks up
244: IPv4 address. */
245: #define ADDRLEN(sa) (((sa)->sa_family == AF_INET ? \
246: sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)))
247:
248: #define SIN(s) ((struct sockaddr_in *)(s))
249: #define SIN6(s) ((struct sockaddr_in6 *)(s))
250:
251: /* Retrieve address information for the given ifp */
252: static int
253: if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label)
254: {
255: int ret;
256: struct lifreq lifreq;
257: struct sockaddr_storage mask, dest;
258: char *dest_pnt = NULL;
259: u_char prefixlen = 0;
260: afi_t af;
261: int flags = 0;
262:
263: /* Interface's name and address family.
264: * We need to use the logical interface name / label, if we've been
265: * given one, in order to get the right address
266: */
267: strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ);
268:
269: /* Interface's address. */
270: memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr));
271: af = addr->sa_family;
272:
273: /* Point to point or broad cast address pointer init. */
274: dest_pnt = NULL;
275:
276: if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0)
277: {
278: memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr));
279: if (af == AF_INET)
280: dest_pnt = (char *) &(SIN (&dest)->sin_addr);
281: else
282: dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr);
283: flags = ZEBRA_IFA_PEER;
284: }
285:
286: if (af == AF_INET)
287: {
288: ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq);
289:
290: if (ret < 0)
291: {
292: if (errno != EADDRNOTAVAIL)
293: {
294: zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name,
295: safe_strerror (errno));
296: return ret;
297: }
298: return 0;
299: }
300: memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr));
301:
302: prefixlen = ip_masklen (SIN (&mask)->sin_addr);
303: if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0))
304: {
305: memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in));
306: dest_pnt = (char *) &SIN (&dest)->sin_addr;
307: }
308: }
309: #ifdef HAVE_IPV6
310: else if (af == AF_INET6)
311: {
312: if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0)
313: {
314: if (ifp->flags & IFF_POINTOPOINT)
315: prefixlen = IPV6_MAX_BITLEN;
316: else
317: zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s",
318: ifp->name, safe_strerror (errno));
319: }
320: else
321: {
322: prefixlen = lifreq.lifr_addrlen;
323: }
324: }
325: #endif /* HAVE_IPV6 */
326:
327: /* Set address to the interface. */
328: if (af == AF_INET)
329: connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen,
330: (struct in_addr *) dest_pnt, label);
331: #ifdef HAVE_IPV6
332: else if (af == AF_INET6)
333: connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen,
334: (struct in6_addr *) dest_pnt, label);
335: #endif /* HAVE_IPV6 */
336:
337: return 0;
338: }
339:
340: /* Fetch interface information via ioctl(). */
341: static void
342: interface_info_ioctl (struct interface *ifp)
343: {
344: if_get_index (ifp);
345: if_get_flags (ifp);
346: if_get_mtu (ifp);
347: if_get_metric (ifp);
348: }
349:
350: /* Lookup all interface information. */
351: void
352: interface_list ()
353: {
354: interface_list_ioctl (AF_INET);
355: interface_list_ioctl (AF_INET6);
356: interface_list_ioctl (AF_UNSPEC);
357: }
358:
359: struct connected *
360: if_lookup_linklocal (struct interface *ifp)
361: {
362: #ifdef HAVE_IPV6
363: struct listnode *node;
364: struct connected *ifc;
365:
366: if (ifp == NULL)
367: return NULL;
368:
369: for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
370: {
371: if ((ifc->address->family == AF_INET6) &&
372: (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6)))
373: return ifc;
374: }
375: #endif /* HAVE_IPV6 */
376:
377: return NULL;
378: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>