1/* 2 * Interface looking up by ioctl (). 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 "if.h" 26#include "sockunion.h" 27#include "prefix.h" 28#include "ioctl.h" 29#include "connected.h" 30#include "memory.h" 31#include "log.h" 32 33#include "zebra/interface.h" 34 35/* Interface looking up using infamous SIOCGIFCONF. */ 36int 37interface_list_ioctl () 38{ 39 int ret; 40 int sock; 41#define IFNUM_BASE 32 42 int ifnum; 43 struct ifreq *ifreq; 44 struct ifconf ifconf; 45 struct interface *ifp; 46 int n; 47 int lastlen; 48 49 /* Normally SIOCGIFCONF works with AF_INET socket. */ 50 sock = socket (AF_INET, SOCK_DGRAM, 0); 51 if (sock < 0) 52 { 53#ifdef FOX_RIP_DEBUG 54 zlog_warn ("Can't make AF_INET socket stream: %s", strerror (errno)); 55#endif /* FOX_RIP_DEBUG */ 56 return -1; 57 } 58 59 /* Set initial ifreq count. This will be double when SIOCGIFCONF 60 fail. Solaris has SIOCGIFNUM. */ 61#ifdef SIOCGIFNUM 62 ret = ioctl (sock, SIOCGIFNUM, &ifnum); 63 if (ret < 0) 64 ifnum = IFNUM_BASE; 65 else 66 ifnum++; 67#else 68 ifnum = IFNUM_BASE; 69#endif /* SIOCGIFNUM */ 70 71 ifconf.ifc_buf = NULL; 72 73 lastlen = 0; 74 /* Loop until SIOCGIFCONF success. */ 75 for (;;) 76 { 77 ifconf.ifc_len = sizeof (struct ifreq) * ifnum; 78 ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len); 79 80 ret = ioctl(sock, SIOCGIFCONF, &ifconf); 81 82 if (ret < 0) 83 { 84#ifdef FOX_RIP_DEBUG 85 zlog_warn ("SIOCGIFCONF: %s", strerror(errno)); 86#endif /* FOX_RIP_DEBUG */ 87 goto end; 88 } 89 /* Repeatedly get info til buffer fails to grow. */ 90 if (ifconf.ifc_len > lastlen) 91 { 92 lastlen = ifconf.ifc_len; 93 ifnum += 10; 94 continue; 95 } 96 /* Success. */ 97 break; 98 } 99 100 /* Allocate interface. */ 101 ifreq = ifconf.ifc_req; 102 103#ifdef OPEN_BSD 104 for (n = 0; n < ifconf.ifc_len; ) 105 { 106 int size; 107 108 ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n); 109 ifp = if_get_by_name (ifreq->ifr_name); 110 if_add_update (ifp); 111 size = ifreq->ifr_addr.sa_len; 112 if (size < sizeof (ifreq->ifr_addr)) 113 size = sizeof (ifreq->ifr_addr); 114 size += sizeof (ifreq->ifr_name); 115 n += size; 116 } 117#else 118 for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) 119 { 120 ifp = if_get_by_name (ifreq->ifr_name); 121 if_add_update (ifp); 122 ifreq++; 123 } 124#endif /* OPEN_BSD */ 125 126 end: 127 close (sock); 128 XFREE (MTYPE_TMP, ifconf.ifc_buf); 129 130 return ret; 131} 132 133/* Get interface's index by ioctl. */ 134int 135if_get_index (struct interface *ifp) 136{ 137 static int if_fake_index = 1; 138 139#ifdef HAVE_BROKEN_ALIASES 140 /* Linux 2.2.X does not provide individual interface index for aliases. */ 141 ifp->ifindex = if_fake_index++; 142 return ifp->ifindex; 143#else 144#ifdef SIOCGIFINDEX 145 int ret; 146 struct ifreq ifreq; 147 148 ifreq_set_name (&ifreq, ifp); 149 150 ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq); 151 if (ret < 0) 152 { 153 /* Linux 2.0.X does not have interface index. */ 154 ifp->ifindex = if_fake_index++; 155 return ifp->ifindex; 156 } 157 158 /* OK we got interface index. */ 159#ifdef ifr_ifindex 160 ifp->ifindex = ifreq.ifr_ifindex; 161#else 162 ifp->ifindex = ifreq.ifr_index; 163#endif 164 return ifp->ifindex; 165 166#else 167 ifp->ifindex = if_fake_index++; 168 return ifp->ifindex; 169#endif /* SIOCGIFINDEX */ 170#endif /* HAVE_BROKEN_ALIASES */ 171} 172 173#ifdef SIOCGIFHWADDR 174int 175if_get_hwaddr (struct interface *ifp) 176{ 177 int ret; 178 struct ifreq ifreq; 179 int i; 180 181 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); 182 ifreq.ifr_addr.sa_family = AF_INET; 183 184 /* Fetch Hardware address if available. */ 185 ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq); 186 if (ret < 0) 187 ifp->hw_addr_len = 0; 188 else 189 { 190 memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6); 191 192 for (i = 0; i < 6; i++) 193 if (ifp->hw_addr[i] != 0) 194 break; 195 196 if (i == 6) 197 ifp->hw_addr_len = 0; 198 else 199 ifp->hw_addr_len = 6; 200 } 201 return 0; 202} 203#endif /* SIOCGIFHWADDR */ 204 205#ifdef HAVE_GETIFADDRS 206#include <ifaddrs.h> 207 208int 209if_getaddrs () 210{ 211 int ret; 212 struct ifaddrs *ifap; 213 struct ifaddrs *ifapfree; 214 struct interface *ifp; 215 int prefixlen; 216 217 ret = getifaddrs (&ifap); 218 if (ret != 0) 219 { 220#ifdef FOX_RIP_DEBUG 221 zlog_err ("getifaddrs(): %s", strerror (errno)); 222#endif /* FOX_RIP_DEBUG */ 223 return -1; 224 } 225 226 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) 227 { 228 ifp = if_lookup_by_name (ifap->ifa_name); 229 if (ifp == NULL) 230 { 231#ifdef FOX_RIP_DEBUG 232 zlog_err ("if_getaddrs(): Can't lookup interface %s\n", 233 ifap->ifa_name); 234#endif /* FOX_RIP_DEBUG */ 235 continue; 236 } 237 238 if (ifap->ifa_addr->sa_family == AF_INET) 239 { 240 struct sockaddr_in *addr; 241 struct sockaddr_in *mask; 242 struct sockaddr_in *dest; 243 struct in_addr *dest_pnt; 244 245 addr = (struct sockaddr_in *) ifap->ifa_addr; 246 mask = (struct sockaddr_in *) ifap->ifa_netmask; 247 prefixlen = ip_masklen (mask->sin_addr); 248 249 dest_pnt = NULL; 250 251 if (ifap->ifa_flags & IFF_POINTOPOINT) 252 { 253 dest = (struct sockaddr_in *) ifap->ifa_dstaddr; 254 dest_pnt = &dest->sin_addr; 255 } 256 257 if (ifap->ifa_flags & IFF_BROADCAST) 258 { 259 dest = (struct sockaddr_in *) ifap->ifa_broadaddr; 260 dest_pnt = &dest->sin_addr; 261 } 262 263 connected_add_ipv4 (ifp, 0, &addr->sin_addr, 264 prefixlen, dest_pnt, NULL); 265 } 266#ifdef HAVE_IPV6 267 if (ifap->ifa_addr->sa_family == AF_INET6) 268 { 269 struct sockaddr_in6 *addr; 270 struct sockaddr_in6 *mask; 271 struct sockaddr_in6 *dest; 272 struct in6_addr *dest_pnt; 273 274 addr = (struct sockaddr_in6 *) ifap->ifa_addr; 275 mask = (struct sockaddr_in6 *) ifap->ifa_netmask; 276 prefixlen = ip6_masklen (mask->sin6_addr); 277 278 dest_pnt = NULL; 279 280 if (ifap->ifa_flags & IFF_POINTOPOINT) 281 { 282 if (ifap->ifa_dstaddr) 283 { 284 dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr; 285 dest_pnt = &dest->sin6_addr; 286 } 287 } 288 289 if (ifap->ifa_flags & IFF_BROADCAST) 290 { 291 if (ifap->ifa_broadaddr) 292 { 293 dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr; 294 dest_pnt = &dest->sin6_addr; 295 } 296 } 297 298 connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt); 299 } 300#endif /* HAVE_IPV6 */ 301 } 302 303 freeifaddrs (ifapfree); 304 305 return 0; 306} 307#else /* HAVE_GETIFADDRS */ 308/* Interface address lookup by ioctl. This function only looks up 309 IPv4 address. */ 310int 311if_get_addr (struct interface *ifp) 312{ 313 int ret; 314 struct ifreq ifreq; 315 struct sockaddr_in addr; 316 struct sockaddr_in mask; 317 struct sockaddr_in dest; 318 struct in_addr *dest_pnt; 319 u_char prefixlen; 320 321 /* Interface's name and address family. */ 322 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); 323 ifreq.ifr_addr.sa_family = AF_INET; 324 325 /* Interface's address. */ 326 ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq); 327 if (ret < 0) 328 { 329 if (errno != EADDRNOTAVAIL) 330 { 331#ifdef FOX_RIP_DEBUG 332 zlog_warn ("SIOCGIFADDR fail: %s", strerror (errno)); 333#endif /* FOX_RIP_DEBUG */ 334 return ret; 335 } 336 return 0; 337 } 338 memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); 339 340 /* Interface's network mask. */ 341 ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq); 342 if (ret < 0) 343 { 344 if (errno != EADDRNOTAVAIL) 345 { 346#ifdef FOX_RIP_DEBUG 347 zlog_warn ("SIOCGIFNETMASK fail: %s", strerror (errno)); 348#endif /* FOX_RIP_DEBUG */ 349 return ret; 350 } 351 return 0; 352 } 353#ifdef ifr_netmask 354 memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in)); 355#else 356 memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); 357#endif /* ifr_netmask */ 358 prefixlen = ip_masklen (mask.sin_addr); 359 360 /* Point to point or borad cast address pointer init. */ 361 dest_pnt = NULL; 362 363 if (ifp->flags & IFF_POINTOPOINT) 364 { 365 ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq); 366 if (ret < 0) 367 { 368 if (errno != EADDRNOTAVAIL) 369 { 370#ifdef FOX_RIP_DEBUG 371 zlog_warn ("SIOCGIFDSTADDR fail: %s", strerror (errno)); 372#endif /* FOX_RIP_DEBUG */ 373 return ret; 374 } 375 return 0; 376 } 377 memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in)); 378 dest_pnt = &dest.sin_addr; 379 } 380 if (ifp->flags & IFF_BROADCAST) 381 { 382 ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq); 383 if (ret < 0) 384 { 385 if (errno != EADDRNOTAVAIL) 386 { 387#ifdef FOX_RIP_DEBUG 388 zlog_warn ("SIOCGIFBRDADDR fail: %s", strerror (errno)); 389#endif /* FOX_RIP_DEBUG */ 390 return ret; 391 } 392 return 0; 393 } 394 memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in)); 395 dest_pnt = &dest.sin_addr; 396 } 397 398 399 /* Set address to the interface. */ 400 connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL); 401 402 return 0; 403} 404#endif /* HAVE_GETIFADDRS */ 405 406/* Fetch interface information via ioctl(). */ 407static void 408interface_info_ioctl () 409{ 410 listnode node; 411 struct interface *ifp; 412 413 for (node = listhead (iflist); node; node = nextnode (node)) 414 { 415 ifp = getdata (node); 416 417 if_get_index (ifp); 418#ifdef SIOCGIFHWADDR 419 if_get_hwaddr (ifp); 420#endif /* SIOCGIFHWADDR */ 421 if_get_flags (ifp); 422#ifndef HAVE_GETIFADDRS 423 if_get_addr (ifp); 424#endif /* ! HAVE_GETIFADDRS */ 425 if_get_mtu (ifp); 426 if_get_metric (ifp); 427 } 428} 429 430/* Lookup all interface information. */ 431void 432interface_list () 433{ 434 /* Linux can do both proc & ioctl, ioctl is the only way to get 435 interface aliases in 2.2 series kernels. */ 436#ifdef HAVE_PROC_NET_DEV 437 interface_list_proc (); 438#endif /* HAVE_PROC_NET_DEV */ 439 interface_list_ioctl (); 440 441 /* After listing is done, get index, address, flags and other 442 interface's information. */ 443 interface_info_ioctl (); 444 445#ifdef HAVE_GETIFADDRS 446 if_getaddrs (); 447#endif /* HAVE_GETIFADDRS */ 448 449#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) 450 /* Linux provides interface's IPv6 address via 451 /proc/net/if_inet6. */ 452 ifaddr_proc_ipv6 (); 453#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */ 454} 455