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
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"
37 #ifdef HAVE_BSD_LINK_DETECT
38 #include <net/if_media.h>
39 #endif /* HAVE_BSD_LINK_DETECT*/
41 extern struct zebra_privs_t zserv_privs
;
43 /* clear and set interface name string */
45 ifreq_set_name (struct ifreq
*ifreq
, struct interface
*ifp
)
47 strncpy (ifreq
->ifr_name
, ifp
->name
, IFNAMSIZ
);
50 /* call ioctl system call */
52 if_ioctl (u_long request
, caddr_t buffer
)
58 if (zserv_privs
.change(ZPRIVS_RAISE
))
59 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
60 sock
= socket (AF_INET
, SOCK_DGRAM
, 0);
63 int save_errno
= errno
;
64 if (zserv_privs
.change(ZPRIVS_LOWER
))
65 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
66 zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno
));
69 if ((ret
= ioctl (sock
, request
, buffer
)) < 0)
71 if (zserv_privs
.change(ZPRIVS_LOWER
))
72 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
84 if_ioctl_ipv6 (u_long request
, caddr_t buffer
)
90 if (zserv_privs
.change(ZPRIVS_RAISE
))
91 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
92 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
95 int save_errno
= errno
;
96 if (zserv_privs
.change(ZPRIVS_LOWER
))
97 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
98 zlog_err("Cannot create IPv6 datagram socket: %s",
99 safe_strerror(save_errno
));
103 if ((ret
= ioctl (sock
, request
, buffer
)) < 0)
105 if (zserv_privs
.change(ZPRIVS_LOWER
))
106 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
118 * get interface metric
119 * -- if value is not avaliable set -1
122 if_get_metric (struct interface
*ifp
)
127 ifreq_set_name (&ifreq
, ifp
);
129 if (if_ioctl (SIOCGIFMETRIC
, (caddr_t
) &ifreq
) < 0)
131 ifp
->metric
= ifreq
.ifr_metric
;
132 if (ifp
->metric
== 0)
134 #else /* SIOCGIFMETRIC */
136 #endif /* SIOCGIFMETRIC */
139 /* get interface MTU */
141 if_get_mtu (struct interface
*ifp
)
145 ifreq_set_name (&ifreq
, ifp
);
147 #if defined(SIOCGIFMTU)
148 if (if_ioctl (SIOCGIFMTU
, (caddr_t
) & ifreq
) < 0)
150 zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
151 ifp
->mtu6
= ifp
->mtu
= -1;
156 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_metric
;
158 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
162 zebra_interface_up_update(ifp
);
165 zlog (NULL
, LOG_INFO
, "Can't lookup mtu on this system");
166 ifp
->mtu6
= ifp
->mtu
= -1;
171 /* Interface address setting via netlink interface. */
173 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
175 return kernel_address_add_ipv4 (ifp
, ifc
);
178 /* Interface address is removed using netlink interface. */
180 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
182 return kernel_address_delete_ipv4 (ifp
, ifc
);
184 #else /* ! HAVE_NETLINK */
185 #ifdef HAVE_STRUCT_IFALIASREQ
186 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
187 has ifaliasreq structure. */
189 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
192 struct ifaliasreq addreq
;
193 struct sockaddr_in addr
;
194 struct sockaddr_in mask
;
195 struct prefix_ipv4
*p
;
197 p
= (struct prefix_ipv4
*) ifc
->address
;
198 rib_lookup_and_pushup (p
, ifp
->vrf_id
);
200 memset (&addreq
, 0, sizeof addreq
);
201 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
203 memset (&addr
, 0, sizeof (struct sockaddr_in
));
204 addr
.sin_addr
= p
->prefix
;
205 addr
.sin_family
= p
->family
;
206 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
207 addr
.sin_len
= sizeof (struct sockaddr_in
);
209 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in
));
211 memset (&mask
, 0, sizeof (struct sockaddr_in
));
212 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
213 mask
.sin_family
= p
->family
;
214 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
215 mask
.sin_len
= sizeof (struct sockaddr_in
);
217 memcpy (&addreq
.ifra_mask
, &mask
, sizeof (struct sockaddr_in
));
219 ret
= if_ioctl (SIOCAIFADDR
, (caddr_t
) &addreq
);
225 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
226 has ifaliasreq structure. */
228 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
231 struct ifaliasreq addreq
;
232 struct sockaddr_in addr
;
233 struct sockaddr_in mask
;
234 struct prefix_ipv4
*p
;
236 p
= (struct prefix_ipv4
*)ifc
->address
;
238 memset (&addreq
, 0, sizeof addreq
);
239 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
241 memset (&addr
, 0, sizeof (struct sockaddr_in
));
242 addr
.sin_addr
= p
->prefix
;
243 addr
.sin_family
= p
->family
;
244 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
245 addr
.sin_len
= sizeof (struct sockaddr_in
);
247 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in
));
249 memset (&mask
, 0, sizeof (struct sockaddr_in
));
250 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
251 mask
.sin_family
= p
->family
;
252 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
253 mask
.sin_len
= sizeof (struct sockaddr_in
);
255 memcpy (&addreq
.ifra_mask
, &mask
, sizeof (struct sockaddr_in
));
257 ret
= if_ioctl (SIOCDIFADDR
, (caddr_t
) &addreq
);
263 /* Set up interface's address, netmask (and broadcas? ). Linux or
264 Solaris uses ifname:number semantics to set IP address aliases. */
266 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
270 struct sockaddr_in addr
;
271 struct sockaddr_in broad
;
272 struct sockaddr_in mask
;
273 struct prefix_ipv4 ifaddr
;
274 struct prefix_ipv4
*p
;
276 p
= (struct prefix_ipv4
*) ifc
->address
;
280 ifreq_set_name (&ifreq
, ifp
);
282 addr
.sin_addr
= p
->prefix
;
283 addr
.sin_family
= p
->family
;
284 memcpy (&ifreq
.ifr_addr
, &addr
, sizeof (struct sockaddr_in
));
285 ret
= if_ioctl (SIOCSIFADDR
, (caddr_t
) &ifreq
);
289 /* We need mask for make broadcast addr. */
290 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
292 if (if_is_broadcast (ifp
))
294 apply_mask_ipv4 (&ifaddr
);
295 addr
.sin_addr
= ifaddr
.prefix
;
297 broad
.sin_addr
.s_addr
= (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
298 broad
.sin_family
= p
->family
;
300 memcpy (&ifreq
.ifr_broadaddr
, &broad
, sizeof (struct sockaddr_in
));
301 ret
= if_ioctl (SIOCSIFBRDADDR
, (caddr_t
) &ifreq
);
306 mask
.sin_family
= p
->family
;
308 memcpy (&mask
, &ifreq
.ifr_addr
, sizeof (mask
));
310 memcpy (&ifreq
.ifr_netmask
, &mask
, sizeof (struct sockaddr_in
));
312 ret
= if_ioctl (SIOCSIFNETMASK
, (caddr_t
) &ifreq
);
319 /* Set up interface's address, netmask (and broadcas? ). Linux or
320 Solaris uses ifname:number semantics to set IP address aliases. */
322 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
326 struct sockaddr_in addr
;
327 struct prefix_ipv4
*p
;
329 p
= (struct prefix_ipv4
*) ifc
->address
;
331 ifreq_set_name (&ifreq
, ifp
);
333 memset (&addr
, 0, sizeof (struct sockaddr_in
));
334 addr
.sin_family
= p
->family
;
335 memcpy (&ifreq
.ifr_addr
, &addr
, sizeof (struct sockaddr_in
));
336 ret
= if_ioctl (SIOCSIFADDR
, (caddr_t
) &ifreq
);
342 #endif /* HAVE_STRUCT_IFALIASREQ */
343 #endif /* HAVE_NETLINK */
345 /* get interface flags */
347 if_get_flags (struct interface
*ifp
)
351 #ifdef HAVE_BSD_LINK_DETECT
352 struct ifmediareq ifmr
;
353 #endif /* HAVE_BSD_LINK_DETECT */
355 ifreq_set_name (&ifreq
, ifp
);
357 ret
= if_ioctl (SIOCGIFFLAGS
, (caddr_t
) &ifreq
);
360 zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno
));
363 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
365 /* Per-default, IFF_RUNNING is held high, unless link-detect says
366 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
367 * following practice on Linux and Solaris kernels
369 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
371 if (CHECK_FLAG (ifp
->status
, ZEBRA_INTERFACE_LINKDETECTION
))
373 (void) memset(&ifmr
, 0, sizeof(ifmr
));
374 strncpy (ifmr
.ifm_name
, ifp
->name
, IFNAMSIZ
);
376 /* Seems not all interfaces implement this ioctl */
377 if (if_ioctl(SIOCGIFMEDIA
, (caddr_t
) &ifmr
) < 0)
378 zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno
));
379 else if (ifmr
.ifm_status
& IFM_AVALID
) /* Link state is valid */
381 if (ifmr
.ifm_status
& IFM_ACTIVE
)
382 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
384 UNSET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
387 #endif /* HAVE_BSD_LINK_DETECT */
389 if_flags_update (ifp
, (ifreq
.ifr_flags
& 0x0000ffff));
392 /* Set interface flags */
394 if_set_flags (struct interface
*ifp
, uint64_t flags
)
399 memset (&ifreq
, 0, sizeof(struct ifreq
));
400 ifreq_set_name (&ifreq
, ifp
);
402 ifreq
.ifr_flags
= ifp
->flags
;
403 ifreq
.ifr_flags
|= flags
;
405 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
409 zlog_info ("can't set interface flags");
415 /* Unset interface's flag. */
417 if_unset_flags (struct interface
*ifp
, uint64_t flags
)
422 memset (&ifreq
, 0, sizeof(struct ifreq
));
423 ifreq_set_name (&ifreq
, ifp
);
425 ifreq
.ifr_flags
= ifp
->flags
;
426 ifreq
.ifr_flags
&= ~flags
;
428 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
432 zlog_info ("can't unset interface flags");
440 /* linux/include/net/ipv6.h */
443 struct in6_addr ifr6_addr
;
444 u_int32_t ifr6_prefixlen
;
447 #endif /* _LINUX_IN6_H */
449 /* Interface's address add/delete functions. */
451 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
454 struct prefix_ipv6
*p
;
455 struct in6_ifreq ifreq
;
457 p
= (struct prefix_ipv6
*) ifc
->address
;
459 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
461 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
462 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
463 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
465 ret
= if_ioctl_ipv6 (SIOCSIFADDR
, (caddr_t
) &ifreq
);
471 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
474 struct prefix_ipv6
*p
;
475 struct in6_ifreq ifreq
;
477 p
= (struct prefix_ipv6
*) ifc
->address
;
479 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
481 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
482 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
483 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
485 ret
= if_ioctl_ipv6 (SIOCDIFADDR
, (caddr_t
) &ifreq
);
489 #else /* LINUX_IPV6 */
490 #ifdef HAVE_STRUCT_IN6_ALIASREQ
491 #ifndef ND6_INFINITE_LIFETIME
492 #define ND6_INFINITE_LIFETIME 0xffffffffL
493 #endif /* ND6_INFINITE_LIFETIME */
495 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
498 struct in6_aliasreq addreq
;
499 struct sockaddr_in6 addr
;
500 struct sockaddr_in6 mask
;
501 struct prefix_ipv6
*p
;
503 p
= (struct prefix_ipv6
* ) ifc
->address
;
505 memset (&addreq
, 0, sizeof addreq
);
506 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
508 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
509 addr
.sin6_addr
= p
->prefix
;
510 addr
.sin6_family
= p
->family
;
511 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
512 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
514 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
516 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
517 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
518 mask
.sin6_family
= p
->family
;
519 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
520 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
522 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
524 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
525 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
527 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
528 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
529 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
532 ret
= if_ioctl_ipv6 (SIOCAIFADDR_IN6
, (caddr_t
) &addreq
);
539 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
542 struct in6_aliasreq addreq
;
543 struct sockaddr_in6 addr
;
544 struct sockaddr_in6 mask
;
545 struct prefix_ipv6
*p
;
547 p
= (struct prefix_ipv6
*) ifc
->address
;
549 memset (&addreq
, 0, sizeof addreq
);
550 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
552 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
553 addr
.sin6_addr
= p
->prefix
;
554 addr
.sin6_family
= p
->family
;
555 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
556 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
558 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
560 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
561 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
562 mask
.sin6_family
= p
->family
;
563 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
564 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
566 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
568 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
569 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
570 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
573 ret
= if_ioctl_ipv6 (SIOCDIFADDR_IN6
, (caddr_t
) &addreq
);
580 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
586 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
590 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
592 #endif /* LINUX_IPV6 */