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