]> git.proxmox.com Git - mirror_frr.git/blame - zebra/if_ioctl_solaris.c
bgpd: don't use BGP_ATTR_VNC(255) unless ENABLE_BGP_VNC_ATTR is defined
[mirror_frr.git] / zebra / if_ioctl_solaris.c
CommitLineData
8842468c 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 *
896014f4
DL
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
8842468c 20 */
21
22#include <zebra.h>
23
ddfeb486
DL
24#ifdef SUNOS_5
25
8842468c 26#include "if.h"
27#include "sockunion.h"
28#include "prefix.h"
29#include "ioctl.h"
30#include "connected.h"
31#include "memory.h"
4a1ab8e4 32#include "zebra_memory.h"
8842468c 33#include "log.h"
48a46fa0 34#include "privs.h"
8f7d9fc0 35#include "vrf.h"
82283592 36#include "vty.h"
174482ef 37#include "lib_errors.h"
8842468c 38
39#include "zebra/interface.h"
8d610213 40#include "zebra/ioctl_solaris.h"
8f7d9fc0 41#include "zebra/rib.h"
8842468c 42
d62a17ae 43static int if_get_addr(struct interface *, struct sockaddr *, const char *);
44static void interface_info_ioctl(struct interface *);
48a46fa0 45extern struct zebra_privs_t zserv_privs;
8842468c 46
d62a17ae 47static int interface_list_ioctl(int af)
8842468c 48{
d62a17ae 49 int ret;
50 int sock;
8842468c 51#define IFNUM_BASE 32
d62a17ae 52 struct lifnum lifn;
53 int ifnum;
54 struct lifreq *lifreq;
55 struct lifconf lifconf;
56 struct interface *ifp;
57 int n;
58 int save_errno;
59 size_t needed, lastneeded = 0;
60 char *buf = NULL;
61
01b9e3fd 62 frr_elevate_privs(&zserv_privs) {
01b9e3fd 63 sock = socket(af, SOCK_DGRAM, 0);
6bb30c2c 64 }
d62a17ae 65
6bb30c2c
DL
66 if (sock < 0) {
67 zlog_warn("Can't make %s socket stream: %s",
68 (af == AF_INET ? "AF_INET" : "AF_INET6"),
69 safe_strerror(errno));
70 return -1;
71 }
d62a17ae 72
6bb30c2c
DL
73calculate_lifc_len:
74 frr_elevate_privs(&zserv_privs) {
01b9e3fd 75 lifn.lifn_family = af;
6bb30c2c
DL
76 lifn.lifn_flags = LIFC_NOXMIT;
77 /* we want NOXMIT interfaces too */
01b9e3fd
DL
78 ret = ioctl(sock, SIOCGLIFNUM, &lifn);
79 save_errno = errno;
d62a17ae 80
01b9e3fd 81 }
d62a17ae 82
83 if (ret < 0) {
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 if (buf != NULL)
100 XFREE(MTYPE_TMP, buf);
0ce1ca80 101 buf = XMALLOC(MTYPE_TMP, needed);
d62a17ae 102 }
103 lastneeded = needed;
104
105 lifconf.lifc_family = af;
106 lifconf.lifc_flags = LIFC_NOXMIT;
107 lifconf.lifc_len = needed;
108 lifconf.lifc_buf = buf;
109
6bb30c2c
DL
110 frr_elevate_privs(&zserv_privs) {
111 ret = ioctl(sock, SIOCGLIFCONF, &lifconf);
112 }
d62a17ae 113
114 if (ret < 0) {
115 if (errno == EINVAL)
6bb30c2c 116 goto calculate_lifc_len;
d62a17ae 117
118 zlog_warn("SIOCGLIFCONF: %s", safe_strerror(errno));
d62a17ae 119 goto end;
120 }
121
d62a17ae 122 /* Allocate interface. */
123 lifreq = lifconf.lifc_req;
124
125 for (n = 0; n < lifconf.lifc_len; n += sizeof(struct lifreq)) {
126 /* we treat Solaris logical interfaces as addresses, because
127 * that is
128 * how PF_ROUTE on Solaris treats them. Hence we can not
129 * directly use
130 * the lifreq_name to get the ifp. We need to normalise the
131 * name
132 * before attempting get.
133 *
134 * Solaris logical interface names are in the form of:
135 * <interface name>:<logical interface id>
136 */
137 unsigned int normallen = 0;
138 uint64_t lifflags;
139
140 /* We should exclude ~IFF_UP interfaces, as we'll find out about
141 * them
142 * coming up later through RTM_NEWADDR message on the route
143 * socket.
144 */
145 if (if_get_flags_direct(lifreq->lifr_name, &lifflags,
146 lifreq->lifr_addr.ss_family)
147 || !CHECK_FLAG(lifflags, IFF_UP)) {
148 lifreq++;
149 continue;
150 }
151
152 /* Find the normalised name */
153 while ((normallen < sizeof(lifreq->lifr_name))
154 && (*(lifreq->lifr_name + normallen) != '\0')
155 && (*(lifreq->lifr_name + normallen) != ':'))
156 normallen++;
157
bcc24579 158 ifp = if_get_by_name(lifreq->lifr_name, VRF_DEFAULT, 0);
d62a17ae 159
160 if (lifreq->lifr_addr.ss_family == AF_INET)
161 ifp->flags |= IFF_IPV4;
162
163 if (lifreq->lifr_addr.ss_family == AF_INET6) {
164 ifp->flags |= IFF_IPV6;
165 }
166
167 if_add_update(ifp);
168
169 interface_info_ioctl(ifp);
170
171 /* If a logical interface pass the full name so it can be
172 * as a label on the address
173 */
174 if (*(lifreq->lifr_name + normallen) != '\0')
175 if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
176 lifreq->lifr_name);
177 else
178 if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
179 NULL);
180
181 /* Poke the interface flags. Lets IFF_UP mangling kick in */
182 if_flags_update(ifp, ifp->flags);
183
184 lifreq++;
185 }
8842468c 186
187end:
d62a17ae 188 close(sock);
189 XFREE(MTYPE_TMP, lifconf.lifc_buf);
190 return ret;
8842468c 191}
192
193/* Get interface's index by ioctl. */
d62a17ae 194static int if_get_index(struct interface *ifp)
8842468c 195{
d62a17ae 196 int ret;
197 struct lifreq lifreq;
8842468c 198
d62a17ae 199 lifreq_set_name(&lifreq, ifp->name);
8842468c 200
d62a17ae 201 if (ifp->flags & IFF_IPV4)
202 ret = AF_IOCTL(AF_INET, SIOCGLIFINDEX, (caddr_t)&lifreq);
203 else if (ifp->flags & IFF_IPV6)
204 ret = AF_IOCTL(AF_INET6, SIOCGLIFINDEX, (caddr_t)&lifreq);
205 else
206 ret = -1;
8842468c 207
d62a17ae 208 if (ret < 0) {
209 zlog_warn("SIOCGLIFINDEX(%s) failed", ifp->name);
210 return ret;
211 }
8842468c 212
d62a17ae 213/* OK we got interface index. */
8842468c 214#ifdef ifr_ifindex
ff880b78 215 if_set_index(ifp, lifreq.lifr_ifindex);
8842468c 216#else
ff880b78 217 if_set_index(ifp, lifreq.lifr_index);
8842468c 218#endif
d62a17ae 219 return ifp->ifindex;
8842468c 220}
221
222
223/* Interface address lookup by ioctl. This function only looks up
224 IPv4 address. */
d62a17ae 225#define ADDRLEN(sa) \
226 (((sa)->sa_family == AF_INET ? sizeof(struct sockaddr_in) \
227 : sizeof(struct sockaddr_in6)))
8842468c 228
229#define SIN(s) ((struct sockaddr_in *)(s))
230#define SIN6(s) ((struct sockaddr_in6 *)(s))
231
0752ef0b 232/* Retrieve address information for the given ifp */
d62a17ae 233static int if_get_addr(struct interface *ifp, struct sockaddr *addr,
234 const char *label)
8842468c 235{
d62a17ae 236 int ret;
237 struct lifreq lifreq;
238 struct sockaddr_storage mask, dest;
239 char *dest_pnt = NULL;
d7c0a89a 240 uint8_t prefixlen = 0;
d62a17ae 241 afi_t af;
242 int flags = 0;
243
244 /* Interface's name and address family.
245 * We need to use the logical interface name / label, if we've been
246 * given one, in order to get the right address
247 */
248 strncpy(lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ);
249
250 /* Interface's address. */
251 memcpy(&lifreq.lifr_addr, addr, ADDRLEN(addr));
252 af = addr->sa_family;
253
254 /* Point to point or broad cast address pointer init. */
255 dest_pnt = NULL;
256
257 if (AF_IOCTL(af, SIOCGLIFDSTADDR, (caddr_t)&lifreq) >= 0) {
258 memcpy(&dest, &lifreq.lifr_dstaddr, ADDRLEN(addr));
259 if (af == AF_INET)
260 dest_pnt = (char *)&(SIN(&dest)->sin_addr);
261 else
262 dest_pnt = (char *)&(SIN6(&dest)->sin6_addr);
263 flags = ZEBRA_IFA_PEER;
fb6724a6 264 }
d62a17ae 265
266 if (af == AF_INET) {
267 ret = if_ioctl(SIOCGLIFNETMASK, (caddr_t)&lifreq);
268
269 if (ret < 0) {
270 if (errno != EADDRNOTAVAIL) {
271 zlog_warn("SIOCGLIFNETMASK (%s) fail: %s",
272 ifp->name, safe_strerror(errno));
273 return ret;
274 }
275 return 0;
276 }
277 memcpy(&mask, &lifreq.lifr_addr, ADDRLEN(addr));
278
279 prefixlen = ip_masklen(SIN(&mask)->sin_addr);
280 if (!dest_pnt
281 && (if_ioctl(SIOCGLIFBRDADDR, (caddr_t)&lifreq) >= 0)) {
282 memcpy(&dest, &lifreq.lifr_broadaddr,
283 sizeof(struct sockaddr_in));
284 dest_pnt = (char *)&SIN(&dest)->sin_addr;
285 }
286 } else if (af == AF_INET6) {
287 if (if_ioctl_ipv6(SIOCGLIFSUBNET, (caddr_t)&lifreq) < 0) {
288 if (ifp->flags & IFF_POINTOPOINT)
289 prefixlen = IPV6_MAX_BITLEN;
290 else
291 zlog_warn("SIOCGLIFSUBNET (%s) fail: %s",
292 ifp->name, safe_strerror(errno));
293 } else {
294 prefixlen = lifreq.lifr_addrlen;
295 }
fb6724a6 296 }
8842468c 297
d62a17ae 298 /* Set address to the interface. */
299 if (af == AF_INET)
300 connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen,
301 (struct in_addr *)dest_pnt, label);
302 else if (af == AF_INET6)
60c0687a 303 connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL,
608105a7 304 prefixlen, label);
8842468c 305
d62a17ae 306 return 0;
8842468c 307}
308
309/* Fetch interface information via ioctl(). */
d62a17ae 310static void interface_info_ioctl(struct interface *ifp)
8842468c 311{
d62a17ae 312 if_get_index(ifp);
313 if_get_flags(ifp);
314 if_get_mtu(ifp);
315 if_get_metric(ifp);
8842468c 316}
317
318/* Lookup all interface information. */
d62a17ae 319void interface_list(struct zebra_ns *zns)
8842468c 320{
d62a17ae 321 if (zns->ns_id != NS_DEFAULT) {
322 zlog_warn("interface_list: ignore NS %u", zns->ns_id);
323 return;
324 }
325 interface_list_ioctl(AF_INET);
326 interface_list_ioctl(AF_INET6);
327 interface_list_ioctl(AF_UNSPEC);
8842468c 328}
329
d62a17ae 330struct connected *if_lookup_linklocal(struct interface *ifp)
8842468c 331{
d62a17ae 332 struct listnode *node;
333 struct connected *ifc;
8842468c 334
d62a17ae 335 if (ifp == NULL)
336 return NULL;
8842468c 337
d62a17ae 338 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
339 if ((ifc->address->family == AF_INET6)
340 && (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)))
341 return ifc;
342 }
5b73a671 343
d62a17ae 344 return NULL;
8842468c 345}
ddfeb486
DL
346
347#endif /* SUNOS_5 */