2 * Common ioctl functions for 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 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
34 #include "lib_errors.h"
36 #include "zebra/rib.h"
38 #include "zebra/interface.h"
39 #include "zebra/ioctl_solaris.h"
40 #include "zebra/zebra_errors.h"
42 extern struct zebra_privs_t zserv_privs
;
44 /* clear and set interface name string */
45 void lifreq_set_name(struct lifreq
*lifreq
, const char *ifname
)
47 strncpy(lifreq
->lifr_name
, ifname
, IFNAMSIZ
);
50 int vrf_if_ioctl(unsigned long request
, caddr_t buffer
, vrf_id_t vrf_id
)
52 return if_ioctl(request
, buffer
);
55 /* call ioctl system call */
56 int if_ioctl(unsigned long request
, caddr_t buffer
)
62 frr_elevate_privs(&zserv_privs
) {
64 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
66 zlog_err("Cannot create UDP socket: %s",
67 safe_strerror(errno
));
71 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
86 int if_ioctl_ipv6(unsigned long request
, caddr_t buffer
)
92 frr_elevate_privs(&zserv_privs
) {
94 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
96 zlog_err("Cannot create IPv6 datagram socket: %s",
97 safe_strerror(errno
));
101 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
117 * get interface metric
118 * -- if value is not avaliable set -1
120 void if_get_metric(struct interface
*ifp
)
122 struct lifreq lifreq
;
125 lifreq_set_name(&lifreq
, ifp
->name
);
127 if (ifp
->flags
& IFF_IPV4
)
128 ret
= AF_IOCTL(AF_INET
, SIOCGLIFMETRIC
, (caddr_t
)&lifreq
);
130 else if (ifp
->flags
& IFF_IPV6
)
131 ret
= AF_IOCTL(AF_INET6
, SIOCGLIFMETRIC
, (caddr_t
)&lifreq
);
132 #endif /* SOLARIS_IPV6 */
139 ifp
->metric
= lifreq
.lifr_metric
;
141 if (ifp
->metric
== 0)
145 /* get interface MTU */
146 void if_get_mtu(struct interface
*ifp
)
148 struct lifreq lifreq
;
152 if (ifp
->flags
& IFF_IPV4
) {
153 lifreq_set_name(&lifreq
, ifp
->name
);
154 ret
= AF_IOCTL(AF_INET
, SIOCGLIFMTU
, (caddr_t
)&lifreq
);
157 "Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)",
161 ifp
->mtu
= lifreq
.lifr_metric
;
166 if (ifp
->flags
& IFF_IPV6
) {
167 memset(&lifreq
, 0, sizeof(lifreq
));
168 lifreq_set_name(&lifreq
, ifp
->name
);
170 ret
= AF_IOCTL(AF_INET6
, SIOCGLIFMTU
, (caddr_t
)&lifreq
);
173 "Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)",
177 ifp
->mtu6
= lifreq
.lifr_metric
;
183 zebra_interface_up_update(ifp
);
186 /* Set up interface's address, netmask (and broadcast? ).
187 Solaris uses ifname:number semantics to set IP address aliases. */
188 int if_set_prefix(struct interface
*ifp
, struct connected
*ifc
)
192 struct sockaddr_in addr
;
193 struct sockaddr_in broad
;
194 struct sockaddr_in mask
;
195 struct prefix_ipv4 ifaddr
;
196 struct prefix_ipv4
*p
;
198 p
= (struct prefix_ipv4
*)ifc
->address
;
202 strncpy(ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
204 addr
.sin_addr
= p
->prefix
;
205 addr
.sin_family
= p
->family
;
206 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
208 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
213 /* We need mask for make broadcast addr. */
214 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
216 if (if_is_broadcast(ifp
)) {
217 apply_mask_ipv4(&ifaddr
);
218 addr
.sin_addr
= ifaddr
.prefix
;
220 broad
.sin_addr
.s_addr
=
221 (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
222 broad
.sin_family
= p
->family
;
224 memcpy(&ifreq
.ifr_broadaddr
, &broad
,
225 sizeof(struct sockaddr_in
));
226 ret
= if_ioctl(SIOCSIFBRDADDR
, (caddr_t
)&ifreq
);
231 mask
.sin_family
= p
->family
;
233 memcpy(&mask
, &ifreq
.ifr_addr
, sizeof(mask
));
235 memcpy(&ifreq
.ifr_netmask
, &mask
, sizeof(struct sockaddr_in
));
237 ret
= if_ioctl(SIOCSIFNETMASK
, (caddr_t
)&ifreq
);
239 return ((ret
< 0) ? ret
: 0);
242 /* Set up interface's address, netmask (and broadcast).
243 Solaris uses ifname:number semantics to set IP address aliases. */
244 int if_unset_prefix(struct interface
*ifp
, struct connected
*ifc
)
248 struct sockaddr_in addr
;
249 struct prefix_ipv4
*p
;
251 p
= (struct prefix_ipv4
*)ifc
->address
;
253 strncpy(ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
255 memset(&addr
, 0, sizeof(struct sockaddr_in
));
256 addr
.sin_family
= p
->family
;
257 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
259 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
267 /* Get just the flags for the given name.
268 * Used by the normal 'if_get_flags' function, as well
269 * as the bootup interface-list code, which has to peek at per-address
270 * flags in order to figure out which ones should be ignored..
272 int if_get_flags_direct(const char *ifname
, uint64_t *flags
, unsigned int af
)
274 struct lifreq lifreq
;
277 lifreq_set_name(&lifreq
, ifname
);
279 ret
= AF_IOCTL(af
, SIOCGLIFFLAGS
, (caddr_t
)&lifreq
);
282 zlog_debug("%s: ifname %s, error %s (%d)", __func__
, ifname
,
283 safe_strerror(errno
), errno
);
285 *flags
= lifreq
.lifr_flags
;
290 /* get interface flags */
291 void if_get_flags(struct interface
*ifp
)
293 int ret4
= 0, ret6
= 0;
294 uint64_t newflags
= 0;
297 if (ifp
->flags
& IFF_IPV4
) {
298 ret4
= if_get_flags_direct(ifp
->name
, &tmpflags
, AF_INET
);
301 newflags
|= tmpflags
;
302 else if (errno
== ENXIO
) {
304 UNSET_FLAG(ifp
->flags
, IFF_UP
);
305 if_flags_update(ifp
, ifp
->flags
);
309 if (ifp
->flags
& IFF_IPV6
) {
310 ret6
= if_get_flags_direct(ifp
->name
, &tmpflags
, AF_INET6
);
313 newflags
|= tmpflags
;
314 else if (errno
== ENXIO
) {
316 UNSET_FLAG(ifp
->flags
, IFF_UP
);
317 if_flags_update(ifp
, ifp
->flags
);
321 /* only update flags if one of above succeeded */
323 if_flags_update(ifp
, newflags
);
326 /* Set interface flags */
327 int if_set_flags(struct interface
*ifp
, uint64_t flags
)
330 struct lifreq lifreq
;
332 lifreq_set_name(&lifreq
, ifp
->name
);
334 lifreq
.lifr_flags
= ifp
->flags
;
335 lifreq
.lifr_flags
|= flags
;
337 if (ifp
->flags
& IFF_IPV4
)
338 ret
= AF_IOCTL(AF_INET
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
339 else if (ifp
->flags
& IFF_IPV6
)
340 ret
= AF_IOCTL(AF_INET6
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
345 zlog_info("can't set interface flags on %s: %s", ifp
->name
,
346 safe_strerror(errno
));
353 /* Unset interface's flag. */
354 int if_unset_flags(struct interface
*ifp
, uint64_t flags
)
357 struct lifreq lifreq
;
359 lifreq_set_name(&lifreq
, ifp
->name
);
361 lifreq
.lifr_flags
= ifp
->flags
;
362 lifreq
.lifr_flags
&= ~flags
;
364 if (ifp
->flags
& IFF_IPV4
)
365 ret
= AF_IOCTL(AF_INET
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
366 else if (ifp
->flags
& IFF_IPV6
)
367 ret
= AF_IOCTL(AF_INET6
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
372 zlog_info("can't unset interface flags");
379 /* Interface's address add/delete functions. */
380 int if_prefix_add_ipv6(struct interface
*ifp
, struct connected
*ifc
)
382 char addrbuf
[PREFIX_STRLEN
];
384 flog_warn(EC_LIB_DEVELOPMENT
, "Can't set %s on interface %s",
385 prefix2str(ifc
->address
, addrbuf
, sizeof(addrbuf
)),
391 int if_prefix_delete_ipv6(struct interface
*ifp
, struct connected
*ifc
)
393 char addrbuf
[PREFIX_STRLEN
];
395 flog_warn(EC_LIB_DEVELOPMENT
, "Can't delete %s on interface %s",
396 prefix2str(ifc
->address
, addrbuf
, sizeof(addrbuf
)),