1/* 2 * Common ioctl functions. 3 * Copyright (C) 1997, 98 Kunihiro Ishiguro 4 * 5 * This file is part of GNU Zebra. 6 * 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 10 * later version. 11 * 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. 16 * 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 20 * 02111-1307, USA. 21 */ 22 23#include <zebra.h> 24 25#include "linklist.h" 26#include "if.h" 27#include "prefix.h" 28#include "ioctl.h" 29#include "log.h" 30#include "privs.h" 31 32#include "zebra/rib.h" 33#include "zebra/rt.h" 34#include "zebra/interface.h" 35 36#ifdef HAVE_BSD_LINK_DETECT 37#include <net/if_media.h> 38#endif /* HAVE_BSD_LINK_DETECT*/ 39 40extern struct zebra_privs_t zserv_privs; 41 42/* clear and set interface name string */ 43void 44ifreq_set_name (struct ifreq *ifreq, struct interface *ifp) 45{ 46 strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ); 47} 48 49/* call ioctl system call */ 50int 51if_ioctl (u_long request, caddr_t buffer) 52{ 53 int sock; 54 int ret; 55 int err; 56 57 if (zserv_privs.change(ZPRIVS_RAISE)) 58 zlog (NULL, LOG_ERR, "Can't raise privileges"); 59 sock = socket (AF_INET, SOCK_DGRAM, 0); 60 if (sock < 0) 61 { 62 int save_errno = errno; 63 if (zserv_privs.change(ZPRIVS_LOWER)) 64 zlog (NULL, LOG_ERR, "Can't lower privileges"); 65 zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno)); 66 exit (1); 67 } 68 if ((ret = ioctl (sock, request, buffer)) < 0) 69 err = errno; 70 if (zserv_privs.change(ZPRIVS_LOWER)) 71 zlog (NULL, LOG_ERR, "Can't lower privileges"); 72 close (sock); 73 74 if (ret < 0) 75 { 76 errno = err; 77 return ret; 78 } 79 return 0; 80} 81 82#ifdef HAVE_IPV6 83static int 84if_ioctl_ipv6 (u_long request, caddr_t buffer) 85{ 86 int sock; 87 int ret; 88 int err; 89 90 if (zserv_privs.change(ZPRIVS_RAISE)) 91 zlog (NULL, LOG_ERR, "Can't raise privileges"); 92 sock = socket (AF_INET6, SOCK_DGRAM, 0); 93 if (sock < 0) 94 { 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)); 100 exit (1); 101 } 102 103 if ((ret = ioctl (sock, request, buffer)) < 0) 104 err = errno; 105 if (zserv_privs.change(ZPRIVS_LOWER)) 106 zlog (NULL, LOG_ERR, "Can't lower privileges"); 107 close (sock); 108 109 if (ret < 0) 110 { 111 errno = err; 112 return ret; 113 } 114 return 0; 115} 116#endif /* HAVE_IPV6 */ 117 118/* 119 * get interface metric 120 * -- if value is not avaliable set -1 121 */ 122void 123if_get_metric (struct interface *ifp) 124{ 125#ifdef SIOCGIFMETRIC 126 struct ifreq ifreq; 127 128 ifreq_set_name (&ifreq, ifp); 129 130 if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0) 131 return; 132 ifp->metric = ifreq.ifr_metric; 133 if (ifp->metric == 0) 134 ifp->metric = 1; 135#else /* SIOCGIFMETRIC */ 136 ifp->metric = -1; 137#endif /* SIOCGIFMETRIC */ 138} 139 140/* get interface MTU */ 141void 142if_get_mtu (struct interface *ifp) 143{ 144 struct ifreq ifreq; 145 146 ifreq_set_name (&ifreq, ifp); 147 148#if defined(SIOCGIFMTU) 149 if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0) 150 { 151 zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)"); 152 ifp->mtu6 = ifp->mtu = -1; 153 return; 154 } 155 156#ifdef SUNOS_5 157 ifp->mtu6 = ifp->mtu = ifreq.ifr_metric; 158#else 159 ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu; 160#endif /* SUNOS_5 */ 161 162 /* propogate */ 163 zebra_interface_up_update(ifp); 164 165#else 166 zlog (NULL, LOG_INFO, "Can't lookup mtu on this system"); 167 ifp->mtu6 = ifp->mtu = -1; 168#endif 169} 170 171#ifdef HAVE_NETLINK 172/* Interface address setting via netlink interface. */ 173int 174if_set_prefix (struct interface *ifp, struct connected *ifc) 175{ 176 return kernel_address_add_ipv4 (ifp, ifc); 177} 178 179/* Interface address is removed using netlink interface. */ 180int 181if_unset_prefix (struct interface *ifp, struct connected *ifc) 182{ 183 return kernel_address_delete_ipv4 (ifp, ifc); 184} 185#else /* ! HAVE_NETLINK */ 186#ifdef HAVE_STRUCT_IFALIASREQ 187/* Set up interface's IP address, netmask (and broadcas? ). *BSD may 188 has ifaliasreq structure. */ 189int 190if_set_prefix (struct interface *ifp, struct connected *ifc) 191{ 192 int ret; 193 struct ifaliasreq addreq; 194 struct sockaddr_in addr; 195 struct sockaddr_in mask; 196 struct prefix_ipv4 *p; 197 198 p = (struct prefix_ipv4 *) ifc->address; 199 rib_lookup_and_pushup (p); 200 201 memset (&addreq, 0, sizeof addreq); 202 strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); 203 204 memset (&addr, 0, sizeof (struct sockaddr_in)); 205 addr.sin_addr = p->prefix; 206 addr.sin_family = p->family; 207#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 208 addr.sin_len = sizeof (struct sockaddr_in); 209#endif 210 memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); 211 212 memset (&mask, 0, sizeof (struct sockaddr_in)); 213 masklen2ip (p->prefixlen, &mask.sin_addr); 214 mask.sin_family = p->family; 215#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 216 mask.sin_len = sizeof (struct sockaddr_in); 217#endif 218 memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); 219 220 ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq); 221 if (ret < 0) 222 return ret; 223 return 0; 224} 225 226/* Set up interface's IP address, netmask (and broadcas? ). *BSD may 227 has ifaliasreq structure. */ 228int 229if_unset_prefix (struct interface *ifp, struct connected *ifc) 230{ 231 int ret; 232 struct ifaliasreq addreq; 233 struct sockaddr_in addr; 234 struct sockaddr_in mask; 235 struct prefix_ipv4 *p; 236 237 p = (struct prefix_ipv4 *)ifc->address; 238 239 memset (&addreq, 0, sizeof addreq); 240 strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); 241 242 memset (&addr, 0, sizeof (struct sockaddr_in)); 243 addr.sin_addr = p->prefix; 244 addr.sin_family = p->family; 245#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 246 addr.sin_len = sizeof (struct sockaddr_in); 247#endif 248 memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); 249 250 memset (&mask, 0, sizeof (struct sockaddr_in)); 251 masklen2ip (p->prefixlen, &mask.sin_addr); 252 mask.sin_family = p->family; 253#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 254 mask.sin_len = sizeof (struct sockaddr_in); 255#endif 256 memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); 257 258 ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq); 259 if (ret < 0) 260 return ret; 261 return 0; 262} 263#else 264/* Set up interface's address, netmask (and broadcas? ). Linux or 265 Solaris uses ifname:number semantics to set IP address aliases. */ 266int 267if_set_prefix (struct interface *ifp, struct connected *ifc) 268{ 269 int ret; 270 struct ifreq ifreq; 271 struct sockaddr_in addr; 272 struct sockaddr_in broad; 273 struct sockaddr_in mask; 274 struct prefix_ipv4 ifaddr; 275 struct prefix_ipv4 *p; 276 277 p = (struct prefix_ipv4 *) ifc->address; 278 279 ifaddr = *p; 280 281 ifreq_set_name (&ifreq, ifp); 282 283 addr.sin_addr = p->prefix; 284 addr.sin_family = p->family; 285 memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); 286 ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq); 287 if (ret < 0) 288 return ret; 289 290 /* We need mask for make broadcast addr. */ 291 masklen2ip (p->prefixlen, &mask.sin_addr); 292 293 if (if_is_broadcast (ifp)) 294 { 295 apply_mask_ipv4 (&ifaddr); 296 addr.sin_addr = ifaddr.prefix; 297 298 broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); 299 broad.sin_family = p->family; 300 301 memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in)); 302 ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq); 303 if (ret < 0) 304 return ret; 305 } 306 307 mask.sin_family = p->family; 308#ifdef SUNOS_5 309 memcpy (&mask, &ifreq.ifr_addr, sizeof (mask)); 310#else 311 memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in)); 312#endif /* SUNOS5 */ 313 ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq); 314 if (ret < 0) 315 return ret; 316 317 return 0; 318} 319 320/* Set up interface's address, netmask (and broadcas? ). Linux or 321 Solaris uses ifname:number semantics to set IP address aliases. */ 322int 323if_unset_prefix (struct interface *ifp, struct connected *ifc) 324{ 325 int ret; 326 struct ifreq ifreq; 327 struct sockaddr_in addr; 328 struct prefix_ipv4 *p; 329 330 p = (struct prefix_ipv4 *) ifc->address; 331 332 ifreq_set_name (&ifreq, ifp); 333 334 memset (&addr, 0, sizeof (struct sockaddr_in)); 335 addr.sin_family = p->family; 336 memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); 337 ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq); 338 if (ret < 0) 339 return ret; 340 341 return 0; 342} 343#endif /* HAVE_STRUCT_IFALIASREQ */ 344#endif /* HAVE_NETLINK */ 345 346/* get interface flags */ 347void 348if_get_flags (struct interface *ifp) 349{ 350 int ret; 351 struct ifreq ifreq; 352#ifdef HAVE_BSD_LINK_DETECT 353 struct ifmediareq ifmr; 354#endif /* HAVE_BSD_LINK_DETECT */ 355 356 ifreq_set_name (&ifreq, ifp); 357 358 ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq); 359 if (ret < 0) 360 { 361 zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno)); 362 return; 363 } 364#ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */ 365 366 /* Per-default, IFF_RUNNING is held high, unless link-detect says 367 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag, 368 * following practice on Linux and Solaris kernels 369 */ 370 SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); 371 372 if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) 373 { 374 (void) memset(&ifmr, 0, sizeof(ifmr)); 375 strncpy (ifmr.ifm_name, ifp->name, IFNAMSIZ); 376 377 /* Seems not all interfaces implement this ioctl */ 378 if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) 379 zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno)); 380 else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */ 381 { 382 if (ifmr.ifm_status & IFM_ACTIVE) 383 SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); 384 else 385 UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); 386 } 387 } 388#endif /* HAVE_BSD_LINK_DETECT */ 389 390 if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff)); 391} 392 393/* Set interface flags */ 394int 395if_set_flags (struct interface *ifp, uint64_t flags) 396{ 397 int ret; 398 struct ifreq ifreq; 399 400 memset (&ifreq, 0, sizeof(struct ifreq)); 401 ifreq_set_name (&ifreq, ifp); 402 403 ifreq.ifr_flags = ifp->flags; 404 ifreq.ifr_flags |= flags; 405 406 ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); 407 408 if (ret < 0) 409 { 410 zlog_info ("can't set interface flags"); 411 return ret; 412 } 413 return 0; 414} 415 416/* Unset interface's flag. */ 417int 418if_unset_flags (struct interface *ifp, uint64_t flags) 419{ 420 int ret; 421 struct ifreq ifreq; 422 423 memset (&ifreq, 0, sizeof(struct ifreq)); 424 ifreq_set_name (&ifreq, ifp); 425 426 ifreq.ifr_flags = ifp->flags; 427 ifreq.ifr_flags &= ~flags; 428 429 ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); 430 431 if (ret < 0) 432 { 433 zlog_info ("can't unset interface flags"); 434 return ret; 435 } 436 return 0; 437} 438 439#ifdef HAVE_IPV6 440 441#ifdef LINUX_IPV6 442#ifndef _LINUX_IN6_H 443/* linux/include/net/ipv6.h */ 444struct in6_ifreq 445{ 446 struct in6_addr ifr6_addr; 447 u_int32_t ifr6_prefixlen; 448 int ifr6_ifindex; 449}; 450#endif /* _LINUX_IN6_H */ 451 452/* Interface's address add/delete functions. */ 453int 454if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) 455{ 456 int ret; 457 struct prefix_ipv6 *p; 458 struct in6_ifreq ifreq; 459 460 p = (struct prefix_ipv6 *) ifc->address; 461 462 memset (&ifreq, 0, sizeof (struct in6_ifreq)); 463 464 memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr)); 465 ifreq.ifr6_ifindex = ifp->ifindex; 466 ifreq.ifr6_prefixlen = p->prefixlen; 467 468 ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq); 469 470 return ret; 471} 472 473int 474if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) 475{ 476 int ret; 477 struct prefix_ipv6 *p; 478 struct in6_ifreq ifreq; 479 480 p = (struct prefix_ipv6 *) ifc->address; 481 482 memset (&ifreq, 0, sizeof (struct in6_ifreq)); 483 484 memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr)); 485 ifreq.ifr6_ifindex = ifp->ifindex; 486 ifreq.ifr6_prefixlen = p->prefixlen; 487 488 ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq); 489 490 return ret; 491} 492#else /* LINUX_IPV6 */ 493#ifdef HAVE_STRUCT_IN6_ALIASREQ 494#ifndef ND6_INFINITE_LIFETIME 495#define ND6_INFINITE_LIFETIME 0xffffffffL 496#endif /* ND6_INFINITE_LIFETIME */ 497int 498if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) 499{ 500 int ret; 501 struct in6_aliasreq addreq; 502 struct sockaddr_in6 addr; 503 struct sockaddr_in6 mask; 504 struct prefix_ipv6 *p; 505 506 p = (struct prefix_ipv6 * ) ifc->address; 507 508 memset (&addreq, 0, sizeof addreq); 509 strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); 510 511 memset (&addr, 0, sizeof (struct sockaddr_in6)); 512 addr.sin6_addr = p->prefix; 513 addr.sin6_family = p->family; 514#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 515 addr.sin6_len = sizeof (struct sockaddr_in6); 516#endif 517 memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6)); 518 519 memset (&mask, 0, sizeof (struct sockaddr_in6)); 520 masklen2ip6 (p->prefixlen, &mask.sin6_addr); 521 mask.sin6_family = p->family; 522#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 523 mask.sin6_len = sizeof (struct sockaddr_in6); 524#endif 525 memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); 526 527 addreq.ifra_lifetime.ia6t_vltime = 0xffffffff; 528 addreq.ifra_lifetime.ia6t_pltime = 0xffffffff; 529 530#ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME 531 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 532 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 533#endif 534 535 ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq); 536 if (ret < 0) 537 return ret; 538 return 0; 539} 540 541int 542if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) 543{ 544 int ret; 545 struct in6_aliasreq addreq; 546 struct sockaddr_in6 addr; 547 struct sockaddr_in6 mask; 548 struct prefix_ipv6 *p; 549 550 p = (struct prefix_ipv6 *) ifc->address; 551 552 memset (&addreq, 0, sizeof addreq); 553 strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); 554 555 memset (&addr, 0, sizeof (struct sockaddr_in6)); 556 addr.sin6_addr = p->prefix; 557 addr.sin6_family = p->family; 558#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 559 addr.sin6_len = sizeof (struct sockaddr_in6); 560#endif 561 memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6)); 562 563 memset (&mask, 0, sizeof (struct sockaddr_in6)); 564 masklen2ip6 (p->prefixlen, &mask.sin6_addr); 565 mask.sin6_family = p->family; 566#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 567 mask.sin6_len = sizeof (struct sockaddr_in6); 568#endif 569 memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); 570 571#ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME 572 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 573 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 574#endif 575 576 ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq); 577 if (ret < 0) 578 return ret; 579 return 0; 580} 581#else 582int 583if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) 584{ 585 return 0; 586} 587 588int 589if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) 590{ 591 return 0; 592} 593#endif /* HAVE_STRUCT_IN6_ALIASREQ */ 594 595#endif /* LINUX_IPV6 */ 596 597#endif /* HAVE_IPV6 */ 598