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");
85 if_ioctl_ipv6 (u_long request
, caddr_t buffer
)
91 if (zserv_privs
.change(ZPRIVS_RAISE
))
92 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
93 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
96 int save_errno
= errno
;
97 if (zserv_privs
.change(ZPRIVS_LOWER
))
98 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
99 zlog_err("Cannot create IPv6 datagram socket: %s",
100 safe_strerror(save_errno
));
104 if ((ret
= ioctl (sock
, request
, buffer
)) < 0)
106 if (zserv_privs
.change(ZPRIVS_LOWER
))
107 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
117 #endif /* HAVE_IPV6 */
120 * get interface metric
121 * -- if value is not avaliable set -1
124 if_get_metric (struct interface
*ifp
)
129 ifreq_set_name (&ifreq
, ifp
);
131 if (if_ioctl (SIOCGIFMETRIC
, (caddr_t
) &ifreq
) < 0)
133 ifp
->metric
= ifreq
.ifr_metric
;
134 if (ifp
->metric
== 0)
136 #else /* SIOCGIFMETRIC */
138 #endif /* SIOCGIFMETRIC */
141 /* get interface MTU */
143 if_get_mtu (struct interface
*ifp
)
147 ifreq_set_name (&ifreq
, ifp
);
149 #if defined(SIOCGIFMTU)
150 if (if_ioctl (SIOCGIFMTU
, (caddr_t
) & ifreq
) < 0)
152 zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
153 ifp
->mtu6
= ifp
->mtu
= -1;
158 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_metric
;
160 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
164 zebra_interface_up_update(ifp
);
167 zlog (NULL
, LOG_INFO
, "Can't lookup mtu on this system");
168 ifp
->mtu6
= ifp
->mtu
= -1;
173 /* Interface address setting via netlink interface. */
175 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
177 return kernel_address_add_ipv4 (ifp
, ifc
);
180 /* Interface address is removed using netlink interface. */
182 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
184 return kernel_address_delete_ipv4 (ifp
, ifc
);
186 #else /* ! HAVE_NETLINK */
187 #ifdef HAVE_STRUCT_IFALIASREQ
188 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
189 has ifaliasreq structure. */
191 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
194 struct ifaliasreq addreq
;
195 struct sockaddr_in addr
;
196 struct sockaddr_in mask
;
197 struct prefix_ipv4
*p
;
199 p
= (struct prefix_ipv4
*) ifc
->address
;
200 rib_lookup_and_pushup (p
, ifp
->vrf_id
);
202 memset (&addreq
, 0, sizeof addreq
);
203 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
205 memset (&addr
, 0, sizeof (struct sockaddr_in
));
206 addr
.sin_addr
= p
->prefix
;
207 addr
.sin_family
= p
->family
;
208 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
209 addr
.sin_len
= sizeof (struct sockaddr_in
);
211 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in
));
213 memset (&mask
, 0, sizeof (struct sockaddr_in
));
214 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
215 mask
.sin_family
= p
->family
;
216 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
217 mask
.sin_len
= sizeof (struct sockaddr_in
);
219 memcpy (&addreq
.ifra_mask
, &mask
, sizeof (struct sockaddr_in
));
221 ret
= if_ioctl (SIOCAIFADDR
, (caddr_t
) &addreq
);
227 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
228 has ifaliasreq structure. */
230 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
233 struct ifaliasreq addreq
;
234 struct sockaddr_in addr
;
235 struct sockaddr_in mask
;
236 struct prefix_ipv4
*p
;
238 p
= (struct prefix_ipv4
*)ifc
->address
;
240 memset (&addreq
, 0, sizeof addreq
);
241 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
243 memset (&addr
, 0, sizeof (struct sockaddr_in
));
244 addr
.sin_addr
= p
->prefix
;
245 addr
.sin_family
= p
->family
;
246 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
247 addr
.sin_len
= sizeof (struct sockaddr_in
);
249 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in
));
251 memset (&mask
, 0, sizeof (struct sockaddr_in
));
252 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
253 mask
.sin_family
= p
->family
;
254 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
255 mask
.sin_len
= sizeof (struct sockaddr_in
);
257 memcpy (&addreq
.ifra_mask
, &mask
, sizeof (struct sockaddr_in
));
259 ret
= if_ioctl (SIOCDIFADDR
, (caddr_t
) &addreq
);
265 /* Set up interface's address, netmask (and broadcas? ). Linux or
266 Solaris uses ifname:number semantics to set IP address aliases. */
268 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
272 struct sockaddr_in addr
;
273 struct sockaddr_in broad
;
274 struct sockaddr_in mask
;
275 struct prefix_ipv4 ifaddr
;
276 struct prefix_ipv4
*p
;
278 p
= (struct prefix_ipv4
*) ifc
->address
;
282 ifreq_set_name (&ifreq
, ifp
);
284 addr
.sin_addr
= p
->prefix
;
285 addr
.sin_family
= p
->family
;
286 memcpy (&ifreq
.ifr_addr
, &addr
, sizeof (struct sockaddr_in
));
287 ret
= if_ioctl (SIOCSIFADDR
, (caddr_t
) &ifreq
);
291 /* We need mask for make broadcast addr. */
292 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
294 if (if_is_broadcast (ifp
))
296 apply_mask_ipv4 (&ifaddr
);
297 addr
.sin_addr
= ifaddr
.prefix
;
299 broad
.sin_addr
.s_addr
= (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
300 broad
.sin_family
= p
->family
;
302 memcpy (&ifreq
.ifr_broadaddr
, &broad
, sizeof (struct sockaddr_in
));
303 ret
= if_ioctl (SIOCSIFBRDADDR
, (caddr_t
) &ifreq
);
308 mask
.sin_family
= p
->family
;
310 memcpy (&mask
, &ifreq
.ifr_addr
, sizeof (mask
));
312 memcpy (&ifreq
.ifr_netmask
, &mask
, sizeof (struct sockaddr_in
));
314 ret
= if_ioctl (SIOCSIFNETMASK
, (caddr_t
) &ifreq
);
321 /* Set up interface's address, netmask (and broadcas? ). Linux or
322 Solaris uses ifname:number semantics to set IP address aliases. */
324 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
328 struct sockaddr_in addr
;
329 struct prefix_ipv4
*p
;
331 p
= (struct prefix_ipv4
*) ifc
->address
;
333 ifreq_set_name (&ifreq
, ifp
);
335 memset (&addr
, 0, sizeof (struct sockaddr_in
));
336 addr
.sin_family
= p
->family
;
337 memcpy (&ifreq
.ifr_addr
, &addr
, sizeof (struct sockaddr_in
));
338 ret
= if_ioctl (SIOCSIFADDR
, (caddr_t
) &ifreq
);
344 #endif /* HAVE_STRUCT_IFALIASREQ */
345 #endif /* HAVE_NETLINK */
347 /* get interface flags */
349 if_get_flags (struct interface
*ifp
)
353 #ifdef HAVE_BSD_LINK_DETECT
354 struct ifmediareq ifmr
;
355 #endif /* HAVE_BSD_LINK_DETECT */
357 ifreq_set_name (&ifreq
, ifp
);
359 ret
= if_ioctl (SIOCGIFFLAGS
, (caddr_t
) &ifreq
);
362 zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno
));
365 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
367 /* Per-default, IFF_RUNNING is held high, unless link-detect says
368 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
369 * following practice on Linux and Solaris kernels
371 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
373 if (CHECK_FLAG (ifp
->status
, ZEBRA_INTERFACE_LINKDETECTION
))
375 (void) memset(&ifmr
, 0, sizeof(ifmr
));
376 strncpy (ifmr
.ifm_name
, ifp
->name
, IFNAMSIZ
);
378 /* Seems not all interfaces implement this ioctl */
379 if (if_ioctl(SIOCGIFMEDIA
, (caddr_t
) &ifmr
) < 0)
380 zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno
));
381 else if (ifmr
.ifm_status
& IFM_AVALID
) /* Link state is valid */
383 if (ifmr
.ifm_status
& IFM_ACTIVE
)
384 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
386 UNSET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
389 #endif /* HAVE_BSD_LINK_DETECT */
391 if_flags_update (ifp
, (ifreq
.ifr_flags
& 0x0000ffff));
394 /* Set interface flags */
396 if_set_flags (struct interface
*ifp
, uint64_t flags
)
401 memset (&ifreq
, 0, sizeof(struct ifreq
));
402 ifreq_set_name (&ifreq
, ifp
);
404 ifreq
.ifr_flags
= ifp
->flags
;
405 ifreq
.ifr_flags
|= flags
;
407 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
411 zlog_info ("can't set interface flags");
417 /* Unset interface's flag. */
419 if_unset_flags (struct interface
*ifp
, uint64_t flags
)
424 memset (&ifreq
, 0, sizeof(struct ifreq
));
425 ifreq_set_name (&ifreq
, ifp
);
427 ifreq
.ifr_flags
= ifp
->flags
;
428 ifreq
.ifr_flags
&= ~flags
;
430 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
434 zlog_info ("can't unset interface flags");
444 /* linux/include/net/ipv6.h */
447 struct in6_addr ifr6_addr
;
448 u_int32_t ifr6_prefixlen
;
451 #endif /* _LINUX_IN6_H */
453 /* Interface's address add/delete functions. */
455 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
458 struct prefix_ipv6
*p
;
459 struct in6_ifreq ifreq
;
461 p
= (struct prefix_ipv6
*) ifc
->address
;
463 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
465 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
466 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
467 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
469 ret
= if_ioctl_ipv6 (SIOCSIFADDR
, (caddr_t
) &ifreq
);
475 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
478 struct prefix_ipv6
*p
;
479 struct in6_ifreq ifreq
;
481 p
= (struct prefix_ipv6
*) ifc
->address
;
483 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
485 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
486 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
487 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
489 ret
= if_ioctl_ipv6 (SIOCDIFADDR
, (caddr_t
) &ifreq
);
493 #else /* LINUX_IPV6 */
494 #ifdef HAVE_STRUCT_IN6_ALIASREQ
495 #ifndef ND6_INFINITE_LIFETIME
496 #define ND6_INFINITE_LIFETIME 0xffffffffL
497 #endif /* ND6_INFINITE_LIFETIME */
499 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
502 struct in6_aliasreq addreq
;
503 struct sockaddr_in6 addr
;
504 struct sockaddr_in6 mask
;
505 struct prefix_ipv6
*p
;
507 p
= (struct prefix_ipv6
* ) ifc
->address
;
509 memset (&addreq
, 0, sizeof addreq
);
510 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
512 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
513 addr
.sin6_addr
= p
->prefix
;
514 addr
.sin6_family
= p
->family
;
515 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
516 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
518 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
520 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
521 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
522 mask
.sin6_family
= p
->family
;
523 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
524 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
526 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
528 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
529 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
531 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
532 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
533 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
536 ret
= if_ioctl_ipv6 (SIOCAIFADDR_IN6
, (caddr_t
) &addreq
);
543 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
546 struct in6_aliasreq addreq
;
547 struct sockaddr_in6 addr
;
548 struct sockaddr_in6 mask
;
549 struct prefix_ipv6
*p
;
551 p
= (struct prefix_ipv6
*) ifc
->address
;
553 memset (&addreq
, 0, sizeof addreq
);
554 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
556 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
557 addr
.sin6_addr
= p
->prefix
;
558 addr
.sin6_family
= p
->family
;
559 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
560 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
562 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
564 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
565 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
566 mask
.sin6_family
= p
->family
;
567 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
568 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
570 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
572 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
573 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
574 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
577 ret
= if_ioctl_ipv6 (SIOCDIFADDR_IN6
, (caddr_t
) &addreq
);
584 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
590 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
594 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
596 #endif /* LINUX_IPV6 */
598 #endif /* HAVE_IPV6 */