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"
36 #include "zebra/zebra_errors.h"
40 #ifdef HAVE_BSD_LINK_DETECT
41 #include <net/if_media.h>
42 #endif /* HAVE_BSD_LINK_DETECT*/
44 extern struct zebra_privs_t zserv_privs
;
46 /* clear and set interface name string */
47 void ifreq_set_name(struct ifreq
*ifreq
, struct interface
*ifp
)
49 strlcpy(ifreq
->ifr_name
, ifp
->name
, sizeof(ifreq
->ifr_name
));
52 /* call ioctl system call */
53 int if_ioctl(unsigned long request
, caddr_t buffer
)
59 frr_elevate_privs(&zserv_privs
) {
60 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
62 zlog_err("Cannot create UDP socket: %s",
63 safe_strerror(errno
));
66 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
78 /* call ioctl system call */
79 int vrf_if_ioctl(unsigned long request
, caddr_t buffer
, vrf_id_t vrf_id
)
85 frr_elevate_privs(&zserv_privs
) {
86 sock
= vrf_socket(AF_INET
, SOCK_DGRAM
, 0, vrf_id
, NULL
);
88 zlog_err("Cannot create UDP socket: %s",
89 safe_strerror(errno
));
92 ret
= vrf_ioctl(vrf_id
, sock
, request
, buffer
);
106 static int if_ioctl_ipv6(unsigned long request
, caddr_t buffer
)
112 frr_elevate_privs(&zserv_privs
) {
113 sock
= socket(AF_INET6
, SOCK_DGRAM
, 0);
115 zlog_err("Cannot create IPv6 datagram socket: %s",
116 safe_strerror(errno
));
120 if ((ret
= ioctl(sock
, request
, buffer
)) < 0)
131 #endif /* ! HAVE_NETLINK */
134 * get interface metric
135 * -- if value is not avaliable set -1
137 void if_get_metric(struct interface
*ifp
)
142 ifreq_set_name(&ifreq
, ifp
);
144 if (vrf_if_ioctl(SIOCGIFMETRIC
, (caddr_t
)&ifreq
, ifp
->vrf_id
) < 0)
146 ifp
->metric
= ifreq
.ifr_metric
;
147 if (ifp
->metric
== 0)
149 #else /* SIOCGIFMETRIC */
151 #endif /* SIOCGIFMETRIC */
154 /* get interface MTU */
155 void if_get_mtu(struct interface
*ifp
)
159 ifreq_set_name(&ifreq
, ifp
);
161 #if defined(SIOCGIFMTU)
162 if (vrf_if_ioctl(SIOCGIFMTU
, (caddr_t
)&ifreq
, ifp
->vrf_id
) < 0) {
163 zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)");
164 ifp
->mtu6
= ifp
->mtu
= -1;
169 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_metric
;
171 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
175 zebra_interface_up_update(ifp
);
178 zlog_info("Can't lookup mtu on this system");
179 ifp
->mtu6
= ifp
->mtu
= -1;
184 /* Interface address setting via netlink interface. */
185 int if_set_prefix(struct interface
*ifp
, struct connected
*ifc
)
187 return kernel_address_add_ipv4(ifp
, ifc
);
190 /* Interface address is removed using netlink interface. */
191 int if_unset_prefix(struct interface
*ifp
, struct connected
*ifc
)
193 return kernel_address_delete_ipv4(ifp
, ifc
);
195 #else /* ! HAVE_NETLINK */
196 #ifdef HAVE_STRUCT_IFALIASREQ
197 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
198 has ifaliasreq structure. */
199 int if_set_prefix(struct interface
*ifp
, struct connected
*ifc
)
202 struct ifaliasreq addreq
;
203 struct sockaddr_in addr
, mask
, peer
;
204 struct prefix_ipv4
*p
;
206 /* don't configure PtP addresses on broadcast ifs or reverse */
207 if (!(ifp
->flags
& IFF_POINTOPOINT
) != !CONNECTED_PEER(ifc
)) {
212 p
= (struct prefix_ipv4
*)ifc
->address
;
213 rib_lookup_and_pushup(p
, ifp
->vrf_id
);
215 memset(&addreq
, 0, sizeof addreq
);
216 strlcpy(addreq
.ifra_name
, ifp
->name
, sizeof(addreq
.ifra_name
));
218 memset(&addr
, 0, sizeof(struct sockaddr_in
));
219 addr
.sin_addr
= p
->prefix
;
220 addr
.sin_family
= p
->family
;
221 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
222 addr
.sin_len
= sizeof(struct sockaddr_in
);
224 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
226 if (CONNECTED_PEER(ifc
)) {
227 p
= (struct prefix_ipv4
*)ifc
->destination
;
228 memset(&mask
, 0, sizeof(struct sockaddr_in
));
229 peer
.sin_addr
= p
->prefix
;
230 peer
.sin_family
= p
->family
;
231 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
232 peer
.sin_len
= sizeof(struct sockaddr_in
);
234 memcpy(&addreq
.ifra_broadaddr
, &peer
,
235 sizeof(struct sockaddr_in
));
238 memset(&mask
, 0, sizeof(struct sockaddr_in
));
239 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
240 mask
.sin_family
= p
->family
;
241 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
242 mask
.sin_len
= sizeof(struct sockaddr_in
);
244 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
246 ret
= if_ioctl(SIOCAIFADDR
, (caddr_t
)&addreq
);
252 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
253 has ifaliasreq structure. */
254 int if_unset_prefix(struct interface
*ifp
, struct connected
*ifc
)
257 struct ifaliasreq addreq
;
258 struct sockaddr_in addr
, mask
, peer
;
259 struct prefix_ipv4
*p
;
261 /* this would probably wreak havoc */
262 if (!(ifp
->flags
& IFF_POINTOPOINT
) != !CONNECTED_PEER(ifc
)) {
267 p
= (struct prefix_ipv4
*)ifc
->address
;
269 memset(&addreq
, 0, sizeof addreq
);
270 strlcpy(addreq
.ifra_name
, ifp
->name
, sizeof(addreq
.ifra_name
));
272 memset(&addr
, 0, sizeof(struct sockaddr_in
));
273 addr
.sin_addr
= p
->prefix
;
274 addr
.sin_family
= p
->family
;
275 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
276 addr
.sin_len
= sizeof(struct sockaddr_in
);
278 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in
));
280 if (CONNECTED_PEER(ifc
)) {
281 p
= (struct prefix_ipv4
*)ifc
->destination
;
282 memset(&mask
, 0, sizeof(struct sockaddr_in
));
283 peer
.sin_addr
= p
->prefix
;
284 peer
.sin_family
= p
->family
;
285 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
286 peer
.sin_len
= sizeof(struct sockaddr_in
);
288 memcpy(&addreq
.ifra_broadaddr
, &peer
,
289 sizeof(struct sockaddr_in
));
292 memset(&mask
, 0, sizeof(struct sockaddr_in
));
293 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
294 mask
.sin_family
= p
->family
;
295 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
296 mask
.sin_len
= sizeof(struct sockaddr_in
);
298 memcpy(&addreq
.ifra_mask
, &mask
, sizeof(struct sockaddr_in
));
300 ret
= if_ioctl(SIOCDIFADDR
, (caddr_t
)&addreq
);
306 /* Set up interface's address, netmask (and broadcas? ). Linux or
307 Solaris uses ifname:number semantics to set IP address aliases. */
308 int if_set_prefix(struct interface
*ifp
, struct connected
*ifc
)
312 struct sockaddr_in addr
;
313 struct sockaddr_in broad
;
314 struct sockaddr_in mask
;
315 struct prefix_ipv4 ifaddr
;
316 struct prefix_ipv4
*p
;
318 p
= (struct prefix_ipv4
*)ifc
->address
;
322 ifreq_set_name(&ifreq
, ifp
);
324 addr
.sin_addr
= p
->prefix
;
325 addr
.sin_family
= p
->family
;
326 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
327 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
331 /* We need mask for make broadcast addr. */
332 masklen2ip(p
->prefixlen
, &mask
.sin_addr
);
334 if (if_is_broadcast(ifp
)) {
335 apply_mask_ipv4(&ifaddr
);
336 addr
.sin_addr
= ifaddr
.prefix
;
338 broad
.sin_addr
.s_addr
=
339 (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
340 broad
.sin_family
= p
->family
;
342 memcpy(&ifreq
.ifr_broadaddr
, &broad
,
343 sizeof(struct sockaddr_in
));
344 ret
= if_ioctl(SIOCSIFBRDADDR
, (caddr_t
)&ifreq
);
349 mask
.sin_family
= p
->family
;
351 memcpy(&mask
, &ifreq
.ifr_addr
, sizeof(mask
));
353 memcpy(&ifreq
.ifr_netmask
, &mask
, sizeof(struct sockaddr_in
));
355 ret
= if_ioctl(SIOCSIFNETMASK
, (caddr_t
)&ifreq
);
362 /* Set up interface's address, netmask (and broadcas? ). Linux or
363 Solaris uses ifname:number semantics to set IP address aliases. */
364 int if_unset_prefix(struct interface
*ifp
, struct connected
*ifc
)
368 struct sockaddr_in addr
;
369 struct prefix_ipv4
*p
;
371 p
= (struct prefix_ipv4
*)ifc
->address
;
373 ifreq_set_name(&ifreq
, ifp
);
375 memset(&addr
, 0, sizeof(struct sockaddr_in
));
376 addr
.sin_family
= p
->family
;
377 memcpy(&ifreq
.ifr_addr
, &addr
, sizeof(struct sockaddr_in
));
378 ret
= if_ioctl(SIOCSIFADDR
, (caddr_t
)&ifreq
);
384 #endif /* HAVE_STRUCT_IFALIASREQ */
385 #endif /* HAVE_NETLINK */
387 /* get interface flags */
388 void if_get_flags(struct interface
*ifp
)
392 #ifdef HAVE_BSD_LINK_DETECT
393 struct ifmediareq ifmr
;
394 #endif /* HAVE_BSD_LINK_DETECT */
396 ifreq_set_name(&ifreq
, ifp
);
398 ret
= vrf_if_ioctl(SIOCGIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
400 flog_err_sys(EC_LIB_SYSTEM_CALL
,
401 "vrf_if_ioctl(SIOCGIFFLAGS) failed: %s",
402 safe_strerror(errno
));
405 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
407 /* Per-default, IFF_RUNNING is held high, unless link-detect says
408 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
409 * following practice on Linux and Solaris kernels
411 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
413 if (CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_LINKDETECTION
)) {
414 (void)memset(&ifmr
, 0, sizeof(ifmr
));
415 strlcpy(ifmr
.ifm_name
, ifp
->name
, sizeof(ifmr
.ifm_name
));
417 /* Seems not all interfaces implement this ioctl */
418 if (if_ioctl(SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == -1 &&
420 flog_err_sys(EC_LIB_SYSTEM_CALL
,
421 "if_ioctl(SIOCGIFMEDIA) failed: %s",
422 safe_strerror(errno
));
423 else if (ifmr
.ifm_status
& IFM_AVALID
) /* Link state is valid */
425 if (ifmr
.ifm_status
& IFM_ACTIVE
)
426 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
428 UNSET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
431 #endif /* HAVE_BSD_LINK_DETECT */
433 if_flags_update(ifp
, (ifreq
.ifr_flags
& 0x0000ffff));
436 /* Set interface flags */
437 int if_set_flags(struct interface
*ifp
, uint64_t flags
)
442 memset(&ifreq
, 0, sizeof(struct ifreq
));
443 ifreq_set_name(&ifreq
, ifp
);
445 ifreq
.ifr_flags
= ifp
->flags
;
446 ifreq
.ifr_flags
|= flags
;
448 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
451 zlog_info("can't set interface flags");
457 /* Unset interface's flag. */
458 int if_unset_flags(struct interface
*ifp
, uint64_t flags
)
463 memset(&ifreq
, 0, sizeof(struct ifreq
));
464 ifreq_set_name(&ifreq
, ifp
);
466 ifreq
.ifr_flags
= ifp
->flags
;
467 ifreq
.ifr_flags
&= ~flags
;
469 ret
= vrf_if_ioctl(SIOCSIFFLAGS
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
472 zlog_info("can't unset interface flags");
480 /* linux/include/net/ipv6.h */
482 struct in6_addr ifr6_addr
;
483 uint32_t ifr6_prefixlen
;
486 #endif /* _LINUX_IN6_H */
487 /* Interface's address add/delete functions. */
488 int if_prefix_add_ipv6(struct interface
*ifp
, struct connected
*ifc
)
491 return kernel_address_add_ipv6(ifp
, ifc
);
492 #endif /* HAVE_NETLINK */
495 int if_prefix_delete_ipv6(struct interface
*ifp
, struct connected
*ifc
)
498 return kernel_address_delete_ipv6(ifp
, ifc
);
499 #endif /* HAVE_NETLINK */
501 #else /* LINUX_IPV6 */
502 #ifdef HAVE_STRUCT_IN6_ALIASREQ
503 #ifndef ND6_INFINITE_LIFETIME
504 #define ND6_INFINITE_LIFETIME 0xffffffffL
505 #endif /* ND6_INFINITE_LIFETIME */
506 int if_prefix_add_ipv6(struct interface
*ifp
, struct connected
*ifc
)
509 struct in6_aliasreq addreq
;
510 struct sockaddr_in6 addr
;
511 struct sockaddr_in6 mask
;
512 struct prefix_ipv6
*p
;
514 p
= (struct prefix_ipv6
*)ifc
->address
;
516 memset(&addreq
, 0, sizeof addreq
);
517 strlcpy(addreq
.ifra_name
, ifp
->name
, sizeof(addreq
.ifra_name
));
519 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
520 addr
.sin6_addr
= p
->prefix
;
521 addr
.sin6_family
= p
->family
;
522 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
523 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
525 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
527 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
528 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
529 mask
.sin6_family
= p
->family
;
530 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
531 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
533 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
535 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
536 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
538 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
539 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
540 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
543 ret
= if_ioctl_ipv6(SIOCAIFADDR_IN6
, (caddr_t
)&addreq
);
549 int if_prefix_delete_ipv6(struct interface
*ifp
, struct connected
*ifc
)
552 struct in6_aliasreq addreq
;
553 struct sockaddr_in6 addr
;
554 struct sockaddr_in6 mask
;
555 struct prefix_ipv6
*p
;
557 p
= (struct prefix_ipv6
*)ifc
->address
;
559 memset(&addreq
, 0, sizeof addreq
);
560 strlcpy(addreq
.ifra_name
, ifp
->name
, sizeof(addreq
.ifra_name
));
562 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
563 addr
.sin6_addr
= p
->prefix
;
564 addr
.sin6_family
= p
->family
;
565 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
566 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
568 memcpy(&addreq
.ifra_addr
, &addr
, sizeof(struct sockaddr_in6
));
570 memset(&mask
, 0, sizeof(struct sockaddr_in6
));
571 masklen2ip6(p
->prefixlen
, &mask
.sin6_addr
);
572 mask
.sin6_family
= p
->family
;
573 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
574 mask
.sin6_len
= sizeof(struct sockaddr_in6
);
576 memcpy(&addreq
.ifra_prefixmask
, &mask
, sizeof(struct sockaddr_in6
));
578 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
579 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
580 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
583 ret
= if_ioctl_ipv6(SIOCDIFADDR_IN6
, (caddr_t
)&addreq
);
589 int if_prefix_add_ipv6(struct interface
*ifp
, struct connected
*ifc
)
594 int if_prefix_delete_ipv6(struct interface
*ifp
, struct connected
*ifc
)
598 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
600 #endif /* LINUX_IPV6 */
602 #endif /* !SUNOS_5 */