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
32 #include "zebra/rib.h"
34 #include "zebra/interface.h"
36 #ifdef HAVE_BSD_LINK_DETECT
37 #include <net/if_media.h>
38 #endif /* HAVE_BSD_LINK_DETECT*/
40 extern struct zebra_privs_t zserv_privs
;
42 /* clear and set interface name string */
44 ifreq_set_name (struct ifreq
*ifreq
, struct interface
*ifp
)
46 strncpy (ifreq
->ifr_name
, ifp
->name
, IFNAMSIZ
);
49 /* call ioctl system call */
51 if_ioctl (u_long request
, caddr_t buffer
)
57 if (zserv_privs
.change(ZPRIVS_RAISE
))
58 zlog_err("Can't raise privileges");
59 sock
= socket (AF_INET
, SOCK_DGRAM
, 0);
62 int save_errno
= errno
;
63 if (zserv_privs
.change(ZPRIVS_LOWER
))
64 zlog_err("Can't lower privileges");
65 zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno
));
68 if ((ret
= ioctl (sock
, request
, buffer
)) < 0)
70 if (zserv_privs
.change(ZPRIVS_LOWER
))
71 zlog_err("Can't lower privileges");
83 if_ioctl_ipv6 (u_long request
, caddr_t buffer
)
89 if (zserv_privs
.change(ZPRIVS_RAISE
))
90 zlog_err("Can't raise privileges");
91 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
94 int save_errno
= errno
;
95 if (zserv_privs
.change(ZPRIVS_LOWER
))
96 zlog_err("Can't lower privileges");
97 zlog_err("Cannot create IPv6 datagram socket: %s",
98 safe_strerror(save_errno
));
102 if ((ret
= ioctl (sock
, request
, buffer
)) < 0)
104 if (zserv_privs
.change(ZPRIVS_LOWER
))
105 zlog_err("Can't lower privileges");
117 * get interface metric
118 * -- if value is not avaliable set -1
121 if_get_metric (struct interface
*ifp
)
126 ifreq_set_name (&ifreq
, ifp
);
128 if (if_ioctl (SIOCGIFMETRIC
, (caddr_t
) &ifreq
) < 0)
130 ifp
->metric
= ifreq
.ifr_metric
;
131 if (ifp
->metric
== 0)
133 #else /* SIOCGIFMETRIC */
135 #endif /* SIOCGIFMETRIC */
138 /* get interface MTU */
140 if_get_mtu (struct interface
*ifp
)
144 ifreq_set_name (&ifreq
, ifp
);
146 #if defined(SIOCGIFMTU)
147 if (if_ioctl (SIOCGIFMTU
, (caddr_t
) & ifreq
) < 0)
149 zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
150 ifp
->mtu6
= ifp
->mtu
= -1;
155 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_metric
;
157 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
161 zebra_interface_up_update(ifp
);
164 zlog_info("Can't lookup mtu on this system");
165 ifp
->mtu6
= ifp
->mtu
= -1;
170 /* Interface address setting via netlink interface. */
172 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
174 return kernel_address_add_ipv4 (ifp
, ifc
);
177 /* Interface address is removed using netlink interface. */
179 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
181 return kernel_address_delete_ipv4 (ifp
, ifc
);
183 #else /* ! HAVE_NETLINK */
184 #ifdef HAVE_STRUCT_IFALIASREQ
185 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
186 has ifaliasreq structure. */
188 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
191 struct ifaliasreq addreq
;
192 struct sockaddr_in addr
;
193 struct sockaddr_in mask
;
194 struct prefix_ipv4
*p
;
196 p
= (struct prefix_ipv4
*) ifc
->address
;
197 rib_lookup_and_pushup (p
, ifp
->vrf_id
);
199 memset (&addreq
, 0, sizeof addreq
);
200 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
202 memset (&addr
, 0, sizeof (struct sockaddr_in
));
203 addr
.sin_addr
= p
->prefix
;
204 addr
.sin_family
= p
->family
;
205 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
206 addr
.sin_len
= sizeof (struct sockaddr_in
);
208 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in
));
210 memset (&mask
, 0, sizeof (struct sockaddr_in
));
211 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
212 mask
.sin_family
= p
->family
;
213 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
214 mask
.sin_len
= sizeof (struct sockaddr_in
);
216 memcpy (&addreq
.ifra_mask
, &mask
, sizeof (struct sockaddr_in
));
218 ret
= if_ioctl (SIOCAIFADDR
, (caddr_t
) &addreq
);
224 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
225 has ifaliasreq structure. */
227 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
230 struct ifaliasreq addreq
;
231 struct sockaddr_in addr
;
232 struct sockaddr_in mask
;
233 struct prefix_ipv4
*p
;
235 p
= (struct prefix_ipv4
*)ifc
->address
;
237 memset (&addreq
, 0, sizeof addreq
);
238 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
240 memset (&addr
, 0, sizeof (struct sockaddr_in
));
241 addr
.sin_addr
= p
->prefix
;
242 addr
.sin_family
= p
->family
;
243 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
244 addr
.sin_len
= sizeof (struct sockaddr_in
);
246 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in
));
248 memset (&mask
, 0, sizeof (struct sockaddr_in
));
249 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
250 mask
.sin_family
= p
->family
;
251 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
252 mask
.sin_len
= sizeof (struct sockaddr_in
);
254 memcpy (&addreq
.ifra_mask
, &mask
, sizeof (struct sockaddr_in
));
256 ret
= if_ioctl (SIOCDIFADDR
, (caddr_t
) &addreq
);
262 /* Set up interface's address, netmask (and broadcas? ). Linux or
263 Solaris uses ifname:number semantics to set IP address aliases. */
265 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
269 struct sockaddr_in addr
;
270 struct sockaddr_in broad
;
271 struct sockaddr_in mask
;
272 struct prefix_ipv4 ifaddr
;
273 struct prefix_ipv4
*p
;
275 p
= (struct prefix_ipv4
*) ifc
->address
;
279 ifreq_set_name (&ifreq
, ifp
);
281 addr
.sin_addr
= p
->prefix
;
282 addr
.sin_family
= p
->family
;
283 memcpy (&ifreq
.ifr_addr
, &addr
, sizeof (struct sockaddr_in
));
284 ret
= if_ioctl (SIOCSIFADDR
, (caddr_t
) &ifreq
);
288 /* We need mask for make broadcast addr. */
289 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
291 if (if_is_broadcast (ifp
))
293 apply_mask_ipv4 (&ifaddr
);
294 addr
.sin_addr
= ifaddr
.prefix
;
296 broad
.sin_addr
.s_addr
= (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
297 broad
.sin_family
= p
->family
;
299 memcpy (&ifreq
.ifr_broadaddr
, &broad
, sizeof (struct sockaddr_in
));
300 ret
= if_ioctl (SIOCSIFBRDADDR
, (caddr_t
) &ifreq
);
305 mask
.sin_family
= p
->family
;
307 memcpy (&mask
, &ifreq
.ifr_addr
, sizeof (mask
));
309 memcpy (&ifreq
.ifr_netmask
, &mask
, sizeof (struct sockaddr_in
));
311 ret
= if_ioctl (SIOCSIFNETMASK
, (caddr_t
) &ifreq
);
318 /* Set up interface's address, netmask (and broadcas? ). Linux or
319 Solaris uses ifname:number semantics to set IP address aliases. */
321 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
325 struct sockaddr_in addr
;
326 struct prefix_ipv4
*p
;
328 p
= (struct prefix_ipv4
*) ifc
->address
;
330 ifreq_set_name (&ifreq
, ifp
);
332 memset (&addr
, 0, sizeof (struct sockaddr_in
));
333 addr
.sin_family
= p
->family
;
334 memcpy (&ifreq
.ifr_addr
, &addr
, sizeof (struct sockaddr_in
));
335 ret
= if_ioctl (SIOCSIFADDR
, (caddr_t
) &ifreq
);
341 #endif /* HAVE_STRUCT_IFALIASREQ */
342 #endif /* HAVE_NETLINK */
344 /* get interface flags */
346 if_get_flags (struct interface
*ifp
)
350 #ifdef HAVE_BSD_LINK_DETECT
351 struct ifmediareq ifmr
;
352 #endif /* HAVE_BSD_LINK_DETECT */
354 ifreq_set_name (&ifreq
, ifp
);
356 ret
= if_ioctl (SIOCGIFFLAGS
, (caddr_t
) &ifreq
);
359 zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno
));
362 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
364 /* Per-default, IFF_RUNNING is held high, unless link-detect says
365 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
366 * following practice on Linux and Solaris kernels
368 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
370 if (CHECK_FLAG (ifp
->status
, ZEBRA_INTERFACE_LINKDETECTION
))
372 (void) memset(&ifmr
, 0, sizeof(ifmr
));
373 strncpy (ifmr
.ifm_name
, ifp
->name
, IFNAMSIZ
);
375 /* Seems not all interfaces implement this ioctl */
376 if (if_ioctl(SIOCGIFMEDIA
, (caddr_t
) &ifmr
) < 0)
377 zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno
));
378 else if (ifmr
.ifm_status
& IFM_AVALID
) /* Link state is valid */
380 if (ifmr
.ifm_status
& IFM_ACTIVE
)
381 SET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
383 UNSET_FLAG(ifreq
.ifr_flags
, IFF_RUNNING
);
386 #endif /* HAVE_BSD_LINK_DETECT */
388 if_flags_update (ifp
, (ifreq
.ifr_flags
& 0x0000ffff));
391 /* Set interface flags */
393 if_set_flags (struct interface
*ifp
, uint64_t flags
)
398 memset (&ifreq
, 0, sizeof(struct ifreq
));
399 ifreq_set_name (&ifreq
, ifp
);
401 ifreq
.ifr_flags
= ifp
->flags
;
402 ifreq
.ifr_flags
|= flags
;
404 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
408 zlog_info ("can't set interface flags");
414 /* Unset interface's flag. */
416 if_unset_flags (struct interface
*ifp
, uint64_t flags
)
421 memset (&ifreq
, 0, sizeof(struct ifreq
));
422 ifreq_set_name (&ifreq
, ifp
);
424 ifreq
.ifr_flags
= ifp
->flags
;
425 ifreq
.ifr_flags
&= ~flags
;
427 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
431 zlog_info ("can't unset interface flags");
439 /* linux/include/net/ipv6.h */
442 struct in6_addr ifr6_addr
;
443 u_int32_t ifr6_prefixlen
;
446 #endif /* _LINUX_IN6_H */
448 /* Interface's address add/delete functions. */
450 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
453 struct prefix_ipv6
*p
;
454 struct in6_ifreq ifreq
;
456 p
= (struct prefix_ipv6
*) ifc
->address
;
458 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
460 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
461 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
462 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
464 ret
= if_ioctl_ipv6 (SIOCSIFADDR
, (caddr_t
) &ifreq
);
470 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
473 struct prefix_ipv6
*p
;
474 struct in6_ifreq ifreq
;
476 p
= (struct prefix_ipv6
*) ifc
->address
;
478 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
480 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
481 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
482 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
484 ret
= if_ioctl_ipv6 (SIOCDIFADDR
, (caddr_t
) &ifreq
);
488 #else /* LINUX_IPV6 */
489 #ifdef HAVE_STRUCT_IN6_ALIASREQ
490 #ifndef ND6_INFINITE_LIFETIME
491 #define ND6_INFINITE_LIFETIME 0xffffffffL
492 #endif /* ND6_INFINITE_LIFETIME */
494 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
497 struct in6_aliasreq addreq
;
498 struct sockaddr_in6 addr
;
499 struct sockaddr_in6 mask
;
500 struct prefix_ipv6
*p
;
502 p
= (struct prefix_ipv6
* ) ifc
->address
;
504 memset (&addreq
, 0, sizeof addreq
);
505 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
507 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
508 addr
.sin6_addr
= p
->prefix
;
509 addr
.sin6_family
= p
->family
;
510 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
511 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
513 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
515 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
516 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
517 mask
.sin6_family
= p
->family
;
518 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
519 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
521 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
523 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
524 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
526 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
527 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
528 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
531 ret
= if_ioctl_ipv6 (SIOCAIFADDR_IN6
, (caddr_t
) &addreq
);
538 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
541 struct in6_aliasreq addreq
;
542 struct sockaddr_in6 addr
;
543 struct sockaddr_in6 mask
;
544 struct prefix_ipv6
*p
;
546 p
= (struct prefix_ipv6
*) ifc
->address
;
548 memset (&addreq
, 0, sizeof addreq
);
549 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
551 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
552 addr
.sin6_addr
= p
->prefix
;
553 addr
.sin6_family
= p
->family
;
554 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
555 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
557 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
559 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
560 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
561 mask
.sin6_family
= p
->family
;
562 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
563 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
565 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
567 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
568 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
569 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
572 ret
= if_ioctl_ipv6 (SIOCDIFADDR_IN6
, (caddr_t
) &addreq
);
579 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
585 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
589 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
591 #endif /* LINUX_IPV6 */