2 * Common ioctl functions.
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
30 #include "lib_errors.h"
33 #include "zebra/rib.h"
35 #include "zebra/interface.h"
39 #ifdef HAVE_BSD_LINK_DETECT
40 #include <net/if_media.h>
41 #endif /* HAVE_BSD_LINK_DETECT*/
43 extern struct zebra_privs_t zserv_privs
;
45 /* clear and set interface name string */
46 void ifreq_set_name(struct ifreq
*ifreq
, struct interface
*ifp
)
48 strlcpy(ifreq
->ifr_name
, ifp
->name
, sizeof(ifreq
->ifr_name
));
51 /* call ioctl system call */
52 int if_ioctl(unsigned long request
, caddr_t buffer
)
58 frr_elevate_privs(&zserv_privs
) {
59 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
61 zlog_err("Cannot create UDP socket: %s",
62 safe_strerror(errno
));
65 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
77 /* call ioctl system call */
78 int vrf_if_ioctl(unsigned long request
, caddr_t buffer
, vrf_id_t vrf_id
)
84 frr_elevate_privs(&zserv_privs
) {
85 sock
= vrf_socket(AF_INET
, SOCK_DGRAM
, 0, vrf_id
, NULL
);
87 zlog_err("Cannot create UDP socket: %s",
88 safe_strerror(errno
));
91 ret
= vrf_ioctl(vrf_id
, sock
, request
, buffer
);
105 static int if_ioctl_ipv6(unsigned long request
, caddr_t buffer
)
111 frr_elevate_privs(&zserv_privs
) {
112 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
114 zlog_err("Cannot create IPv6 datagram socket: %s",
115 safe_strerror(errno
));
119 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
130 #endif /* ! HAVE_NETLINK */
133 * get interface metric
134 * -- if value is not avaliable set -1
136 void if_get_metric(struct interface
*ifp
)
141 ifreq_set_name(&ifreq
, ifp
);
143 if (vrf_if_ioctl(SIOCGIFMETRIC
, (caddr_t
)&ifreq
, ifp
->vrf_id
) < 0)
145 ifp
->metric
= ifreq
.ifr_metric
;
146 if (ifp
->metric
== 0)
148 #else /* SIOCGIFMETRIC */
150 #endif /* SIOCGIFMETRIC */
153 /* get interface MTU */
154 void if_get_mtu(struct interface
*ifp
)
158 ifreq_set_name(&ifreq
, ifp
);
160 #if defined(SIOCGIFMTU)
161 if (vrf_if_ioctl(SIOCGIFMTU
, (caddr_t
)&ifreq
, ifp
->vrf_id
) < 0) {
162 zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)");
163 ifp
->mtu6
= ifp
->mtu
= -1;
168 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_metric
;
170 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
174 zebra_interface_up_update(ifp
);
177 zlog_info("Can't lookup mtu on this system");
178 ifp
->mtu6
= ifp
->mtu
= -1;
183 /* Interface address setting via netlink interface. */
184 int if_set_prefix(struct interface
*ifp
, struct connected
*ifc
)
186 return kernel_address_add_ipv4(ifp
, ifc
);
189 /* Interface address is removed using netlink interface. */
190 int if_unset_prefix(struct interface
*ifp
, struct connected
*ifc
)
192 return kernel_address_delete_ipv4(ifp
, ifc
);
194 #else /* ! HAVE_NETLINK */
195 #ifdef HAVE_STRUCT_IFALIASREQ
196 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
197 has ifaliasreq structure. */
198 int if_set_prefix(struct interface
*ifp
, struct connected
*ifc
)
201 struct ifaliasreq addreq
;
202 struct sockaddr_in addr
, mask
, peer
;
203 struct prefix_ipv4
*p
;
205 /* don't configure PtP addresses on broadcast ifs or reverse */
206 if (!(ifp
->flags
& IFF_POINTOPOINT
) != !CONNECTED_PEER(ifc
)) {
211 p
= (struct prefix_ipv4
*)ifc
->address
;
212 rib_lookup_and_pushup(p
, ifp
->vrf_id
);
214 memset(&addreq
, 0, sizeof addreq
);
215 strncpy((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
217 memset(&addr
, 0, sizeof(struct sockaddr_in
));
218 addr
.sin_addr
= p
->prefix
;
219 addr
.sin_family
= p
->family
;
220 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
221 addr
.sin_len
= sizeof(struct sockaddr_in
);
223 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
225 if (CONNECTED_PEER(ifc
)) {
226 p
= (struct prefix_ipv4
*)ifc
->destination
;
227 memset(&mask
, 0, sizeof(struct sockaddr_in
));
228 peer
.sin_addr
= p
->prefix
;
229 peer
.sin_family
= p
->family
;
230 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
231 peer
.sin_len
= sizeof(struct sockaddr_in
);
233 memcpy(&addreq
.ifra_broadaddr
, &peer
,
234 sizeof(struct sockaddr_in
));
237 memset(&mask
, 0, sizeof(struct sockaddr_in
));
238 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
239 mask
.sin_family
= p
->family
;
240 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
241 mask
.sin_len
= sizeof(struct sockaddr_in
);
243 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
245 ret
= if_ioctl(SIOCAIFADDR
, (caddr_t
)&addreq
);
251 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
252 has ifaliasreq structure. */
253 int if_unset_prefix(struct interface
*ifp
, struct connected
*ifc
)
256 struct ifaliasreq addreq
;
257 struct sockaddr_in addr
, mask
, peer
;
258 struct prefix_ipv4
*p
;
260 /* this would probably wreak havoc */
261 if (!(ifp
->flags
& IFF_POINTOPOINT
) != !CONNECTED_PEER(ifc
)) {
266 p
= (struct prefix_ipv4
*)ifc
->address
;
268 memset(&addreq
, 0, sizeof addreq
);
269 strncpy((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
271 memset(&addr
, 0, sizeof(struct sockaddr_in
));
272 addr
.sin_addr
= p
->prefix
;
273 addr
.sin_family
= p
->family
;
274 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
275 addr
.sin_len
= sizeof(struct sockaddr_in
);
277 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
279 if (CONNECTED_PEER(ifc
)) {
280 p
= (struct prefix_ipv4
*)ifc
->destination
;
281 memset(&mask
, 0, sizeof(struct sockaddr_in
));
282 peer
.sin_addr
= p
->prefix
;
283 peer
.sin_family
= p
->family
;
284 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
285 peer
.sin_len
= sizeof(struct sockaddr_in
);
287 memcpy(&addreq
.ifra_broadaddr
, &peer
,
288 sizeof(struct sockaddr_in
));
291 memset(&mask
, 0, sizeof(struct sockaddr_in
));
292 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
293 mask
.sin_family
= p
->family
;
294 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
295 mask
.sin_len
= sizeof(struct sockaddr_in
);
297 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
299 ret
= if_ioctl(SIOCDIFADDR
, (caddr_t
)&addreq
);
305 /* Set up interface's address, netmask (and broadcas? ). Linux or
306 Solaris uses ifname:number semantics to set IP address aliases. */
307 int if_set_prefix(struct interface
*ifp
, struct connected
*ifc
)
311 struct sockaddr_in addr
;
312 struct sockaddr_in broad
;
313 struct sockaddr_in mask
;
314 struct prefix_ipv4 ifaddr
;
315 struct prefix_ipv4
*p
;
317 p
= (struct prefix_ipv4
*)ifc
->address
;
321 ifreq_set_name(&ifreq
, ifp
);
323 addr
.sin_addr
= p
->prefix
;
324 addr
.sin_family
= p
->family
;
325 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
326 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
330 /* We need mask for make broadcast addr. */
331 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
333 if (if_is_broadcast(ifp
)) {
334 apply_mask_ipv4(&ifaddr
);
335 addr
.sin_addr
= ifaddr
.prefix
;
337 broad
.sin_addr
.s_addr
=
338 (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
339 broad
.sin_family
= p
->family
;
341 memcpy(&ifreq
.ifr_broadaddr
, &broad
,
342 sizeof(struct sockaddr_in
));
343 ret
= if_ioctl(SIOCSIFBRDADDR
, (caddr_t
)&ifreq
);
348 mask
.sin_family
= p
->family
;
350 memcpy(&mask
, &ifreq
.ifr_addr
, sizeof(mask
));
352 memcpy(&ifreq
.ifr_netmask
, &mask
, sizeof(struct sockaddr_in
));
354 ret
= if_ioctl(SIOCSIFNETMASK
, (caddr_t
)&ifreq
);
361 /* Set up interface's address, netmask (and broadcas? ). Linux or
362 Solaris uses ifname:number semantics to set IP address aliases. */
363 int if_unset_prefix(struct interface
*ifp
, struct connected
*ifc
)
367 struct sockaddr_in addr
;
368 struct prefix_ipv4
*p
;
370 p
= (struct prefix_ipv4
*)ifc
->address
;
372 ifreq_set_name(&ifreq
, ifp
);
374 memset(&addr
, 0, sizeof(struct sockaddr_in
));
375 addr
.sin_family
= p
->family
;
376 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
377 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
383 #endif /* HAVE_STRUCT_IFALIASREQ */
384 #endif /* HAVE_NETLINK */
386 /* get interface flags */
387 void if_get_flags(struct interface
*ifp
)
391 #ifdef HAVE_BSD_LINK_DETECT
392 struct ifmediareq ifmr
;
393 #endif /* HAVE_BSD_LINK_DETECT */
395 ifreq_set_name(&ifreq
, ifp
);
397 ret
= vrf_if_ioctl(SIOCGIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
399 flog_err_sys(LIB_ERR_SYSTEM_CALL
,
400 "vrf_if_ioctl(SIOCGIFFLAGS) failed: %s",
401 safe_strerror(errno
));
404 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
406 /* Per-default, IFF_RUNNING is held high, unless link-detect says
407 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
408 * following practice on Linux and Solaris kernels
410 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
412 if (CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_LINKDETECTION
)) {
413 (void)memset(&ifmr
, 0, sizeof(ifmr
));
414 strncpy(ifmr
.ifm_name
, ifp
->name
, IFNAMSIZ
);
416 /* Seems not all interfaces implement this ioctl */
417 if (if_ioctl(SIOCGIFMEDIA
, (caddr_t
)&ifmr
) < 0)
418 flog_err_sys(LIB_ERR_SYSTEM_CALL
,
419 "if_ioctl(SIOCGIFMEDIA) failed: %s",
420 safe_strerror(errno
));
421 else if (ifmr
.ifm_status
& IFM_AVALID
) /* Link state is valid */
423 if (ifmr
.ifm_status
& IFM_ACTIVE
)
424 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
426 UNSET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
429 #endif /* HAVE_BSD_LINK_DETECT */
431 if_flags_update(ifp
, (ifreq
.ifr_flags
& 0x0000ffff));
434 /* Set interface flags */
435 int if_set_flags(struct interface
*ifp
, uint64_t flags
)
440 memset(&ifreq
, 0, sizeof(struct ifreq
));
441 ifreq_set_name(&ifreq
, ifp
);
443 ifreq
.ifr_flags
= ifp
->flags
;
444 ifreq
.ifr_flags
|= flags
;
446 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
449 zlog_info("can't set interface flags");
455 /* Unset interface's flag. */
456 int if_unset_flags(struct interface
*ifp
, uint64_t flags
)
461 memset(&ifreq
, 0, sizeof(struct ifreq
));
462 ifreq_set_name(&ifreq
, ifp
);
464 ifreq
.ifr_flags
= ifp
->flags
;
465 ifreq
.ifr_flags
&= ~flags
;
467 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
470 zlog_info("can't unset interface flags");
478 /* linux/include/net/ipv6.h */
480 struct in6_addr ifr6_addr
;
481 uint32_t ifr6_prefixlen
;
484 #endif /* _LINUX_IN6_H */
485 /* Interface's address add/delete functions. */
486 int if_prefix_add_ipv6(struct interface
*ifp
, struct connected
*ifc
)
489 return kernel_address_add_ipv6(ifp
, ifc
);
490 #endif /* HAVE_NETLINK */
493 int if_prefix_delete_ipv6(struct interface
*ifp
, struct connected
*ifc
)
496 return kernel_address_delete_ipv6(ifp
, ifc
);
497 #endif /* HAVE_NETLINK */
499 #else /* LINUX_IPV6 */
500 #ifdef HAVE_STRUCT_IN6_ALIASREQ
501 #ifndef ND6_INFINITE_LIFETIME
502 #define ND6_INFINITE_LIFETIME 0xffffffffL
503 #endif /* ND6_INFINITE_LIFETIME */
504 int if_prefix_add_ipv6(struct interface
*ifp
, struct connected
*ifc
)
507 struct in6_aliasreq addreq
;
508 struct sockaddr_in6 addr
;
509 struct sockaddr_in6 mask
;
510 struct prefix_ipv6
*p
;
512 p
= (struct prefix_ipv6
*)ifc
->address
;
514 memset(&addreq
, 0, sizeof addreq
);
515 strncpy((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
517 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
518 addr
.sin6_addr
= p
->prefix
;
519 addr
.sin6_family
= p
->family
;
520 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
521 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
523 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
525 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
526 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
527 mask
.sin6_family
= p
->family
;
528 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
529 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
531 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
533 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
534 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
536 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
537 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
538 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
541 ret
= if_ioctl_ipv6(SIOCAIFADDR_IN6
, (caddr_t
)&addreq
);
547 int if_prefix_delete_ipv6(struct interface
*ifp
, struct connected
*ifc
)
550 struct in6_aliasreq addreq
;
551 struct sockaddr_in6 addr
;
552 struct sockaddr_in6 mask
;
553 struct prefix_ipv6
*p
;
555 p
= (struct prefix_ipv6
*)ifc
->address
;
557 memset(&addreq
, 0, sizeof addreq
);
558 strncpy((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
560 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
561 addr
.sin6_addr
= p
->prefix
;
562 addr
.sin6_family
= p
->family
;
563 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
564 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
566 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
568 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
569 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
570 mask
.sin6_family
= p
->family
;
571 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
572 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
574 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
576 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
577 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
578 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
581 ret
= if_ioctl_ipv6(SIOCDIFADDR_IN6
, (caddr_t
)&addreq
);
587 int if_prefix_add_ipv6(struct interface
*ifp
, struct connected
*ifc
)
592 int if_prefix_delete_ipv6(struct interface
*ifp
, struct connected
*ifc
)
596 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
598 #endif /* LINUX_IPV6 */
600 #endif /* !SUNOS_5 */