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
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
33 #include "zebra/rib.h"
35 #include "zebra/interface.h"
36 #include "zebra/ioctl_solaris.h"
38 extern struct zebra_privs_t zserv_privs
;
40 /* clear and set interface name string */
41 void lifreq_set_name(struct lifreq
*lifreq
, const char *ifname
)
43 strncpy(lifreq
->lifr_name
, ifname
, IFNAMSIZ
);
46 /* call ioctl system call */
47 int if_ioctl(u_long request
, caddr_t buffer
)
53 if (zserv_privs
.change(ZPRIVS_RAISE
))
54 zlog_err("Can't raise privileges");
56 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
58 int save_errno
= errno
;
59 if (zserv_privs
.change(ZPRIVS_LOWER
))
60 zlog_err("Can't lower privileges");
61 zlog_err("Cannot create UDP socket: %s",
62 safe_strerror(save_errno
));
66 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
69 if (zserv_privs
.change(ZPRIVS_LOWER
))
70 zlog_err("Can't lower privileges");
82 int if_ioctl_ipv6(u_long request
, caddr_t buffer
)
88 if (zserv_privs
.change(ZPRIVS_RAISE
))
89 zlog_err("Can't raise privileges");
91 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
93 int save_errno
= errno
;
94 if (zserv_privs
.change(ZPRIVS_LOWER
))
95 zlog_err("Can't lower privileges");
96 zlog_err("Cannot create IPv6 datagram socket: %s",
97 safe_strerror(save_errno
));
101 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
104 if (zserv_privs
.change(ZPRIVS_LOWER
))
105 zlog_err("Can't lower privileges");
118 * get interface metric
119 * -- if value is not avaliable set -1
121 void if_get_metric(struct interface
*ifp
)
123 struct lifreq lifreq
;
126 lifreq_set_name(&lifreq
, ifp
->name
);
128 if (ifp
->flags
& IFF_IPV4
)
129 ret
= AF_IOCTL(AF_INET
, SIOCGLIFMETRIC
, (caddr_t
)&lifreq
);
131 else if (ifp
->flags
& IFF_IPV6
)
132 ret
= AF_IOCTL(AF_INET6
, SIOCGLIFMETRIC
, (caddr_t
)&lifreq
);
133 #endif /* SOLARIS_IPV6 */
140 ifp
->metric
= lifreq
.lifr_metric
;
142 if (ifp
->metric
== 0)
146 /* get interface MTU */
147 void if_get_mtu(struct interface
*ifp
)
149 struct lifreq lifreq
;
153 if (ifp
->flags
& IFF_IPV4
) {
154 lifreq_set_name(&lifreq
, ifp
->name
);
155 ret
= AF_IOCTL(AF_INET
, SIOCGLIFMTU
, (caddr_t
)&lifreq
);
158 "Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)",
162 ifp
->mtu
= lifreq
.lifr_metric
;
167 if (ifp
->flags
& IFF_IPV6
) {
168 memset(&lifreq
, 0, sizeof(lifreq
));
169 lifreq_set_name(&lifreq
, ifp
->name
);
171 ret
= AF_IOCTL(AF_INET6
, SIOCGLIFMTU
, (caddr_t
)&lifreq
);
174 "Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)",
178 ifp
->mtu6
= lifreq
.lifr_metric
;
184 zebra_interface_up_update(ifp
);
187 /* Set up interface's address, netmask (and broadcast? ).
188 Solaris uses ifname:number semantics to set IP address aliases. */
189 int if_set_prefix(struct interface
*ifp
, struct connected
*ifc
)
193 struct sockaddr_in addr
;
194 struct sockaddr_in broad
;
195 struct sockaddr_in mask
;
196 struct prefix_ipv4 ifaddr
;
197 struct prefix_ipv4
*p
;
199 p
= (struct prefix_ipv4
*)ifc
->address
;
203 strncpy(ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
205 addr
.sin_addr
= p
->prefix
;
206 addr
.sin_family
= p
->family
;
207 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
209 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
214 /* We need mask for make broadcast addr. */
215 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
217 if (if_is_broadcast(ifp
)) {
218 apply_mask_ipv4(&ifaddr
);
219 addr
.sin_addr
= ifaddr
.prefix
;
221 broad
.sin_addr
.s_addr
=
222 (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
223 broad
.sin_family
= p
->family
;
225 memcpy(&ifreq
.ifr_broadaddr
, &broad
,
226 sizeof(struct sockaddr_in
));
227 ret
= if_ioctl(SIOCSIFBRDADDR
, (caddr_t
)&ifreq
);
232 mask
.sin_family
= p
->family
;
234 memcpy(&mask
, &ifreq
.ifr_addr
, sizeof(mask
));
236 memcpy(&ifreq
.ifr_netmask
, &mask
, sizeof(struct sockaddr_in
));
238 ret
= if_ioctl(SIOCSIFNETMASK
, (caddr_t
)&ifreq
);
240 return ((ret
< 0) ? ret
: 0);
243 /* Set up interface's address, netmask (and broadcast).
244 Solaris uses ifname:number semantics to set IP address aliases. */
245 int if_unset_prefix(struct interface
*ifp
, struct connected
*ifc
)
249 struct sockaddr_in addr
;
250 struct prefix_ipv4
*p
;
252 p
= (struct prefix_ipv4
*)ifc
->address
;
254 strncpy(ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
256 memset(&addr
, 0, sizeof(struct sockaddr_in
));
257 addr
.sin_family
= p
->family
;
258 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
260 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
268 /* Get just the flags for the given name.
269 * Used by the normal 'if_get_flags' function, as well
270 * as the bootup interface-list code, which has to peek at per-address
271 * flags in order to figure out which ones should be ignored..
273 int if_get_flags_direct(const char *ifname
, uint64_t *flags
, unsigned int af
)
275 struct lifreq lifreq
;
278 lifreq_set_name(&lifreq
, ifname
);
280 ret
= AF_IOCTL(af
, SIOCGLIFFLAGS
, (caddr_t
)&lifreq
);
283 zlog_debug("%s: ifname %s, error %s (%d)", __func__
, ifname
,
284 safe_strerror(errno
), errno
);
286 *flags
= lifreq
.lifr_flags
;
291 /* get interface flags */
292 void if_get_flags(struct interface
*ifp
)
294 int ret4
= 0, ret6
= 0;
295 uint64_t newflags
= 0;
298 if (ifp
->flags
& IFF_IPV4
) {
299 ret4
= if_get_flags_direct(ifp
->name
, &tmpflags
, AF_INET
);
302 newflags
|= tmpflags
;
303 else if (errno
== ENXIO
) {
305 UNSET_FLAG(ifp
->flags
, IFF_UP
);
306 if_flags_update(ifp
, ifp
->flags
);
310 if (ifp
->flags
& IFF_IPV6
) {
311 ret6
= if_get_flags_direct(ifp
->name
, &tmpflags
, AF_INET6
);
314 newflags
|= tmpflags
;
315 else if (errno
== ENXIO
) {
317 UNSET_FLAG(ifp
->flags
, IFF_UP
);
318 if_flags_update(ifp
, ifp
->flags
);
322 /* only update flags if one of above succeeded */
324 if_flags_update(ifp
, newflags
);
327 /* Set interface flags */
328 int if_set_flags(struct interface
*ifp
, uint64_t flags
)
331 struct lifreq lifreq
;
333 lifreq_set_name(&lifreq
, ifp
->name
);
335 lifreq
.lifr_flags
= ifp
->flags
;
336 lifreq
.lifr_flags
|= flags
;
338 if (ifp
->flags
& IFF_IPV4
)
339 ret
= AF_IOCTL(AF_INET
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
340 else if (ifp
->flags
& IFF_IPV6
)
341 ret
= AF_IOCTL(AF_INET6
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
346 zlog_info("can't set interface flags on %s: %s", ifp
->name
,
347 safe_strerror(errno
));
354 /* Unset interface's flag. */
355 int if_unset_flags(struct interface
*ifp
, uint64_t flags
)
358 struct lifreq lifreq
;
360 lifreq_set_name(&lifreq
, ifp
->name
);
362 lifreq
.lifr_flags
= ifp
->flags
;
363 lifreq
.lifr_flags
&= ~flags
;
365 if (ifp
->flags
& IFF_IPV4
)
366 ret
= AF_IOCTL(AF_INET
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
367 else if (ifp
->flags
& IFF_IPV6
)
368 ret
= AF_IOCTL(AF_INET6
, SIOCSLIFFLAGS
, (caddr_t
)&lifreq
);
373 zlog_info("can't unset interface flags");
380 /* Interface's address add/delete functions. */
381 int if_prefix_add_ipv6(struct interface
*ifp
, struct connected
*ifc
)
383 char addrbuf
[PREFIX_STRLEN
];
385 zlog_warn("Can't set %s on interface %s",
386 prefix2str(ifc
->address
, addrbuf
, sizeof(addrbuf
)),
392 int if_prefix_delete_ipv6(struct interface
*ifp
, struct connected
*ifc
)
394 char addrbuf
[PREFIX_STRLEN
];
396 zlog_warn("Can't delete %s on interface %s",
397 prefix2str(ifc
->address
, addrbuf
, sizeof(addrbuf
)),