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
32 #include "zebra/rib.h"
34 #include "zebra/interface.h"
36 extern struct zebra_privs_t zserv_privs
;
38 /* clear and set interface name string */
40 ifreq_set_name (struct ifreq
*ifreq
, struct interface
*ifp
)
42 strncpy (ifreq
->ifr_name
, ifp
->name
, IFNAMSIZ
);
45 /* call ioctl system call */
47 if_ioctl (u_long request
, caddr_t buffer
)
53 if (zserv_privs
.change(ZPRIVS_RAISE
))
54 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
55 sock
= socket (AF_INET
, SOCK_DGRAM
, 0);
58 int save_errno
= errno
;
59 if (zserv_privs
.change(ZPRIVS_LOWER
))
60 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
61 zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno
));
64 if ((ret
= ioctl (sock
, request
, buffer
)) < 0)
66 if (zserv_privs
.change(ZPRIVS_LOWER
))
67 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
80 if_ioctl_ipv6 (u_long request
, caddr_t buffer
)
86 if (zserv_privs
.change(ZPRIVS_RAISE
))
87 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
88 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
91 int save_errno
= errno
;
92 if (zserv_privs
.change(ZPRIVS_LOWER
))
93 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
94 zlog_err("Cannot create IPv6 datagram socket: %s",
95 safe_strerror(save_errno
));
99 if ((ret
= ioctl (sock
, request
, buffer
)) < 0)
101 if (zserv_privs
.change(ZPRIVS_LOWER
))
102 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
112 #endif /* HAVE_IPV6 */
115 * get interface metric
116 * -- if value is not avaliable set -1
119 if_get_metric (struct interface
*ifp
)
124 ifreq_set_name (&ifreq
, ifp
);
126 if (if_ioctl (SIOCGIFMETRIC
, (caddr_t
) &ifreq
) < 0)
128 ifp
->metric
= ifreq
.ifr_metric
;
129 if (ifp
->metric
== 0)
131 #else /* SIOCGIFMETRIC */
133 #endif /* SIOCGIFMETRIC */
136 /* get interface MTU */
138 if_get_mtu (struct interface
*ifp
)
142 ifreq_set_name (&ifreq
, ifp
);
144 #if defined(SIOCGIFMTU)
145 if (if_ioctl (SIOCGIFMTU
, (caddr_t
) & ifreq
) < 0)
147 zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
148 ifp
->mtu6
= ifp
->mtu
= -1;
153 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_metric
;
155 ifp
->mtu6
= ifp
->mtu
= ifreq
.ifr_mtu
;
159 zebra_interface_up_update(ifp
);
162 zlog (NULL
, LOG_INFO
, "Can't lookup mtu on this system");
163 ifp
->mtu6
= ifp
->mtu
= -1;
168 /* Interface address setting via netlink interface. */
170 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
172 return kernel_address_add_ipv4 (ifp
, ifc
);
175 /* Interface address is removed using netlink interface. */
177 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
179 return kernel_address_delete_ipv4 (ifp
, ifc
);
181 #else /* ! HAVE_NETLINK */
182 #ifdef HAVE_STRUCT_IFALIASREQ
183 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
184 has ifaliasreq structure. */
186 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
189 struct ifaliasreq addreq
;
190 struct sockaddr_in addr
;
191 struct sockaddr_in mask
;
192 struct prefix_ipv4
*p
;
194 p
= (struct prefix_ipv4
*) ifc
->address
;
196 memset (&addreq
, 0, sizeof addreq
);
197 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
199 memset (&addr
, 0, sizeof (struct sockaddr_in
));
200 addr
.sin_addr
= p
->prefix
;
201 addr
.sin_family
= p
->family
;
202 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
203 addr
.sin_len
= sizeof (struct sockaddr_in
);
205 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in
));
207 memset (&mask
, 0, sizeof (struct sockaddr_in
));
208 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
209 mask
.sin_family
= p
->family
;
210 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
211 mask
.sin_len
= sizeof (struct sockaddr_in
);
213 memcpy (&addreq
.ifra_mask
, &mask
, sizeof (struct sockaddr_in
));
215 ret
= if_ioctl (SIOCAIFADDR
, (caddr_t
) &addreq
);
221 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
222 has ifaliasreq structure. */
224 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
227 struct ifaliasreq addreq
;
228 struct sockaddr_in addr
;
229 struct sockaddr_in mask
;
230 struct prefix_ipv4
*p
;
232 p
= (struct prefix_ipv4
*)ifc
->address
;
234 memset (&addreq
, 0, sizeof addreq
);
235 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
237 memset (&addr
, 0, sizeof (struct sockaddr_in
));
238 addr
.sin_addr
= p
->prefix
;
239 addr
.sin_family
= p
->family
;
240 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
241 addr
.sin_len
= sizeof (struct sockaddr_in
);
243 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in
));
245 memset (&mask
, 0, sizeof (struct sockaddr_in
));
246 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
247 mask
.sin_family
= p
->family
;
248 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
249 mask
.sin_len
= sizeof (struct sockaddr_in
);
251 memcpy (&addreq
.ifra_mask
, &mask
, sizeof (struct sockaddr_in
));
253 ret
= if_ioctl (SIOCDIFADDR
, (caddr_t
) &addreq
);
259 /* Set up interface's address, netmask (and broadcas? ). Linux or
260 Solaris uses ifname:number semantics to set IP address aliases. */
262 if_set_prefix (struct interface
*ifp
, struct connected
*ifc
)
266 struct sockaddr_in addr
;
267 struct sockaddr_in broad
;
268 struct sockaddr_in mask
;
269 struct prefix_ipv4 ifaddr
;
270 struct prefix_ipv4
*p
;
272 p
= (struct prefix_ipv4
*) ifc
->address
;
276 ifreq_set_name (&ifreq
, ifp
);
278 addr
.sin_addr
= p
->prefix
;
279 addr
.sin_family
= p
->family
;
280 memcpy (&ifreq
.ifr_addr
, &addr
, sizeof (struct sockaddr_in
));
281 ret
= if_ioctl (SIOCSIFADDR
, (caddr_t
) &ifreq
);
285 /* We need mask for make broadcast addr. */
286 masklen2ip (p
->prefixlen
, &mask
.sin_addr
);
288 if (if_is_broadcast (ifp
))
290 apply_mask_ipv4 (&ifaddr
);
291 addr
.sin_addr
= ifaddr
.prefix
;
293 broad
.sin_addr
.s_addr
= (addr
.sin_addr
.s_addr
| ~mask
.sin_addr
.s_addr
);
294 broad
.sin_family
= p
->family
;
296 memcpy (&ifreq
.ifr_broadaddr
, &broad
, sizeof (struct sockaddr_in
));
297 ret
= if_ioctl (SIOCSIFBRDADDR
, (caddr_t
) &ifreq
);
302 mask
.sin_family
= p
->family
;
304 memcpy (&mask
, &ifreq
.ifr_addr
, sizeof (mask
));
306 memcpy (&ifreq
.ifr_netmask
, &mask
, sizeof (struct sockaddr_in
));
308 ret
= if_ioctl (SIOCSIFNETMASK
, (caddr_t
) &ifreq
);
315 /* Set up interface's address, netmask (and broadcas? ). Linux or
316 Solaris uses ifname:number semantics to set IP address aliases. */
318 if_unset_prefix (struct interface
*ifp
, struct connected
*ifc
)
322 struct sockaddr_in addr
;
323 struct prefix_ipv4
*p
;
325 p
= (struct prefix_ipv4
*) ifc
->address
;
327 ifreq_set_name (&ifreq
, ifp
);
329 memset (&addr
, 0, sizeof (struct sockaddr_in
));
330 addr
.sin_family
= p
->family
;
331 memcpy (&ifreq
.ifr_addr
, &addr
, sizeof (struct sockaddr_in
));
332 ret
= if_ioctl (SIOCSIFADDR
, (caddr_t
) &ifreq
);
338 #endif /* HAVE_STRUCT_IFALIASREQ */
339 #endif /* HAVE_NETLINK */
341 /* get interface flags */
343 if_get_flags (struct interface
*ifp
)
348 ifreq_set_name (&ifreq
, ifp
);
350 ret
= if_ioctl (SIOCGIFFLAGS
, (caddr_t
) &ifreq
);
353 zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno
));
357 if_flags_update (ifp
, (ifreq
.ifr_flags
& 0x0000ffff));
360 /* Set interface flags */
362 if_set_flags (struct interface
*ifp
, uint64_t flags
)
367 memset (&ifreq
, 0, sizeof(struct ifreq
));
368 ifreq_set_name (&ifreq
, ifp
);
370 ifreq
.ifr_flags
= ifp
->flags
;
371 ifreq
.ifr_flags
|= flags
;
373 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
377 zlog_info ("can't set interface flags");
383 /* Unset interface's flag. */
385 if_unset_flags (struct interface
*ifp
, uint64_t flags
)
390 memset (&ifreq
, 0, sizeof(struct ifreq
));
391 ifreq_set_name (&ifreq
, ifp
);
393 ifreq
.ifr_flags
= ifp
->flags
;
394 ifreq
.ifr_flags
&= ~flags
;
396 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
400 zlog_info ("can't unset interface flags");
410 /* linux/include/net/ipv6.h */
413 struct in6_addr ifr6_addr
;
414 u_int32_t ifr6_prefixlen
;
417 #endif /* _LINUX_IN6_H */
419 /* Interface's address add/delete functions. */
421 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
424 struct prefix_ipv6
*p
;
425 struct in6_ifreq ifreq
;
427 p
= (struct prefix_ipv6
*) ifc
->address
;
429 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
431 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
432 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
433 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
435 ret
= if_ioctl_ipv6 (SIOCSIFADDR
, (caddr_t
) &ifreq
);
441 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
444 struct prefix_ipv6
*p
;
445 struct in6_ifreq ifreq
;
447 p
= (struct prefix_ipv6
*) ifc
->address
;
449 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
451 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
452 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
453 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
455 ret
= if_ioctl_ipv6 (SIOCDIFADDR
, (caddr_t
) &ifreq
);
459 #else /* LINUX_IPV6 */
460 #ifdef HAVE_STRUCT_IN6_ALIASREQ
461 #ifndef ND6_INFINITE_LIFETIME
462 #define ND6_INFINITE_LIFETIME 0xffffffffL
463 #endif /* ND6_INFINITE_LIFETIME */
465 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
468 struct in6_aliasreq addreq
;
469 struct sockaddr_in6 addr
;
470 struct sockaddr_in6 mask
;
471 struct prefix_ipv6
*p
;
473 p
= (struct prefix_ipv6
* ) ifc
->address
;
475 memset (&addreq
, 0, sizeof addreq
);
476 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
478 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
479 addr
.sin6_addr
= p
->prefix
;
480 addr
.sin6_family
= p
->family
;
481 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
482 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
484 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
486 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
487 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
488 mask
.sin6_family
= p
->family
;
489 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
490 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
492 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
494 addreq
.ifra_lifetime
.ia6t_vltime
= 0xffffffff;
495 addreq
.ifra_lifetime
.ia6t_pltime
= 0xffffffff;
497 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
498 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
499 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
502 ret
= if_ioctl_ipv6 (SIOCAIFADDR_IN6
, (caddr_t
) &addreq
);
509 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
512 struct in6_aliasreq addreq
;
513 struct sockaddr_in6 addr
;
514 struct sockaddr_in6 mask
;
515 struct prefix_ipv6
*p
;
517 p
= (struct prefix_ipv6
*) ifc
->address
;
519 memset (&addreq
, 0, sizeof addreq
);
520 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
522 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
523 addr
.sin6_addr
= p
->prefix
;
524 addr
.sin6_family
= p
->family
;
525 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
526 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
528 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
530 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
531 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
532 mask
.sin6_family
= p
->family
;
533 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
534 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
536 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
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 (SIOCDIFADDR_IN6
, (caddr_t
) &addreq
);
550 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
556 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
560 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
562 #endif /* LINUX_IPV6 */
564 #endif /* HAVE_IPV6 */