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"
35 extern struct zebra_privs_t zserv_privs
;
37 /* clear and set interface name string */
39 ifreq_set_name (struct ifreq
*ifreq
, struct interface
*ifp
)
41 strncpy (ifreq
->ifr_name
, ifp
->name
, IFNAMSIZ
);
44 /* call ioctl system call */
46 if_ioctl (u_long request
, caddr_t buffer
)
52 if (zserv_privs
.change(ZPRIVS_RAISE
))
53 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
54 sock
= socket (AF_INET
, SOCK_DGRAM
, 0);
57 if (zserv_privs
.change(ZPRIVS_LOWER
))
58 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
62 ret
= ioctl (sock
, request
, buffer
);
63 if (zserv_privs
.change(ZPRIVS_LOWER
))
64 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
81 if_ioctl_ipv6 (u_long request
, caddr_t buffer
)
87 if (zserv_privs
.change(ZPRIVS_RAISE
))
88 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
89 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
92 if (zserv_privs
.change(ZPRIVS_LOWER
))
93 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
98 ret
= ioctl (sock
, request
, buffer
);
99 if (zserv_privs
.change(ZPRIVS_LOWER
))
100 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
115 #endif /* HAVE_IPV6 */
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)");
156 ifp
->mtu
= ifreq
.ifr_metric
;
158 ifp
->mtu
= ifreq
.ifr_mtu
;
162 zlog (NULL
, LOG_INFO
, "Can't lookup mtu on this system");
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_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
;
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
;
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
;
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
;
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_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
);
357 ifp
->flags
= ifreq
.ifr_flags
& 0x0000ffff;
360 /* Set interface flags */
362 if_set_flags (struct interface
*ifp
, unsigned long flags
)
367 ifreq_set_name (&ifreq
, ifp
);
369 ifreq
.ifr_flags
= ifp
->flags
;
370 ifreq
.ifr_flags
|= flags
;
372 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
376 zlog_info ("can't set interface flags");
382 /* Unset interface's flag. */
384 if_unset_flags (struct interface
*ifp
, unsigned long flags
)
389 ifreq_set_name (&ifreq
, ifp
);
391 ifreq
.ifr_flags
= ifp
->flags
;
392 ifreq
.ifr_flags
&= ~flags
;
394 ret
= if_ioctl (SIOCSIFFLAGS
, (caddr_t
) &ifreq
);
398 zlog_info ("can't unset interface flags");
408 /* linux/include/net/ipv6.h */
411 struct in6_addr ifr6_addr
;
412 u_int32_t ifr6_prefixlen
;
415 #endif /* _LINUX_IN6_H */
417 /* Interface's address add/delete functions. */
419 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
422 struct prefix_ipv6
*p
;
423 struct in6_ifreq ifreq
;
425 p
= (struct prefix_ipv6
*) ifc
->address
;
427 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
429 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
430 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
431 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
433 ret
= if_ioctl_ipv6 (SIOCSIFADDR
, (caddr_t
) &ifreq
);
439 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
442 struct prefix_ipv6
*p
;
443 struct in6_ifreq ifreq
;
445 p
= (struct prefix_ipv6
*) ifc
->address
;
447 memset (&ifreq
, 0, sizeof (struct in6_ifreq
));
449 memcpy (&ifreq
.ifr6_addr
, &p
->prefix
, sizeof (struct in6_addr
));
450 ifreq
.ifr6_ifindex
= ifp
->ifindex
;
451 ifreq
.ifr6_prefixlen
= p
->prefixlen
;
453 ret
= if_ioctl_ipv6 (SIOCDIFADDR
, (caddr_t
) &ifreq
);
457 #else /* LINUX_IPV6 */
458 #ifdef HAVE_IN6_ALIASREQ
459 #ifndef ND6_INFINITE_LIFETIME
460 #define ND6_INFINITE_LIFETIME 0xffffffffL
461 #endif /* ND6_INFINITE_LIFETIME */
463 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
466 struct in6_aliasreq addreq
;
467 struct sockaddr_in6 addr
;
468 struct sockaddr_in6 mask
;
469 struct prefix_ipv6
*p
;
471 p
= (struct prefix_ipv6
* ) ifc
->address
;
473 memset (&addreq
, 0, sizeof addreq
);
474 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
476 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
477 addr
.sin6_addr
= p
->prefix
;
478 addr
.sin6_family
= p
->family
;
480 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
482 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
484 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
485 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
486 mask
.sin6_family
= p
->family
;
488 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
490 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
492 #ifdef HAVE_IFRA_LIFETIME
493 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
494 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
497 ret
= if_ioctl_ipv6 (SIOCAIFADDR_IN6
, (caddr_t
) &addreq
);
504 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
507 struct in6_aliasreq addreq
;
508 struct sockaddr_in6 addr
;
509 struct sockaddr_in6 mask
;
510 struct prefix_ipv6
*p
;
512 p
= (struct prefix_ipv6
*) ifc
->address
;
514 memset (&addreq
, 0, sizeof addreq
);
515 strncpy ((char *)&addreq
.ifra_name
, ifp
->name
, sizeof addreq
.ifra_name
);
517 memset (&addr
, 0, sizeof (struct sockaddr_in6
));
518 addr
.sin6_addr
= p
->prefix
;
519 addr
.sin6_family
= p
->family
;
521 addr
.sin6_len
= sizeof (struct sockaddr_in6
);
523 memcpy (&addreq
.ifra_addr
, &addr
, sizeof (struct sockaddr_in6
));
525 memset (&mask
, 0, sizeof (struct sockaddr_in6
));
526 masklen2ip6 (p
->prefixlen
, &mask
.sin6_addr
);
527 mask
.sin6_family
= p
->family
;
529 mask
.sin6_len
= sizeof (struct sockaddr_in6
);
531 memcpy (&addreq
.ifra_prefixmask
, &mask
, sizeof (struct sockaddr_in6
));
533 #ifdef HAVE_IFRA_LIFETIME
534 addreq
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
535 addreq
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
538 ret
= if_ioctl_ipv6 (SIOCDIFADDR_IN6
, (caddr_t
) &addreq
);
545 if_prefix_add_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
551 if_prefix_delete_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
555 #endif /* HAVE_IN6_ALIASREQ */
557 #endif /* LINUX_IPV6 */
559 #endif /* HAVE_IPV6 */