]> git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / zebra / if_ioctl.c
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 along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <zebra.h>
23
24 #include "if.h"
25 #include "sockunion.h"
26 #include "prefix.h"
27 #include "ioctl.h"
28 #include "connected.h"
29 #include "memory.h"
30 #include "zebra_memory.h"
31 #include "log.h"
32 #include "vrf.h"
33 #include "vty.h"
34
35 #include "zebra/interface.h"
36 #include "zebra/rib.h"
37
38 #include <ifaddrs.h>
39
40 /* Interface looking up using infamous SIOCGIFCONF. */
41 static int
42 interface_list_ioctl (void)
43 {
44 int ret;
45 int sock;
46 #define IFNUM_BASE 32
47 int ifnum;
48 struct ifreq *ifreq;
49 struct ifconf ifconf;
50 struct interface *ifp;
51 int n;
52 int lastlen;
53
54 /* Normally SIOCGIFCONF works with AF_INET socket. */
55 sock = socket (AF_INET, SOCK_DGRAM, 0);
56 if (sock < 0)
57 {
58 zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
59 return -1;
60 }
61
62 /* Set initial ifreq count. This will be double when SIOCGIFCONF
63 fail. Solaris has SIOCGIFNUM. */
64 #ifdef SIOCGIFNUM
65 ret = ioctl (sock, SIOCGIFNUM, &ifnum);
66 if (ret < 0)
67 ifnum = IFNUM_BASE;
68 else
69 ifnum++;
70 #else
71 ifnum = IFNUM_BASE;
72 #endif /* SIOCGIFNUM */
73
74 ifconf.ifc_buf = NULL;
75
76 lastlen = 0;
77 /* Loop until SIOCGIFCONF success. */
78 for (;;)
79 {
80 ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
81 ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
82
83 ret = ioctl(sock, SIOCGIFCONF, &ifconf);
84
85 if (ret < 0)
86 {
87 zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
88 goto end;
89 }
90 /* Repeatedly get info til buffer fails to grow. */
91 if (ifconf.ifc_len > lastlen)
92 {
93 lastlen = ifconf.ifc_len;
94 ifnum += 10;
95 continue;
96 }
97 /* Success. */
98 break;
99 }
100
101 /* Allocate interface. */
102 ifreq = ifconf.ifc_req;
103
104 #ifdef OPEN_BSD
105 for (n = 0; n < ifconf.ifc_len; )
106 {
107 unsigned int size;
108
109 ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
110 ifp = if_get_by_name_len(ifreq->ifr_name,
111 strnlen(ifreq->ifr_name,
112 sizeof(ifreq->ifr_name)),
113 VRF_DEFAULT, 0);
114 if_add_update (ifp);
115 size = ifreq->ifr_addr.sa_len;
116 if (size < sizeof (ifreq->ifr_addr))
117 size = sizeof (ifreq->ifr_addr);
118 size += sizeof (ifreq->ifr_name);
119 n += size;
120 }
121 #else
122 for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
123 {
124 ifp = if_get_by_name_len(ifreq->ifr_name,
125 strnlen(ifreq->ifr_name,
126 sizeof(ifreq->ifr_name)),
127 VRF_DEFAULT, 0);
128 if_add_update (ifp);
129 ifreq++;
130 }
131 #endif /* OPEN_BSD */
132
133 end:
134 close (sock);
135 XFREE (MTYPE_TMP, ifconf.ifc_buf);
136
137 return ret;
138 }
139
140 /* Get interface's index by ioctl. */
141 static int
142 if_get_index (struct interface *ifp)
143 {
144 ifp->ifindex = if_nametoindex(ifp->name);
145 return ifp->ifindex;
146 }
147
148 #ifdef SIOCGIFHWADDR
149 static int
150 if_get_hwaddr (struct interface *ifp)
151 {
152 int ret;
153 struct ifreq ifreq;
154 int i;
155
156 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
157 ifreq.ifr_addr.sa_family = AF_INET;
158
159 /* Fetch Hardware address if available. */
160 ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
161 if (ret < 0)
162 ifp->hw_addr_len = 0;
163 else
164 {
165 memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
166
167 for (i = 0; i < 6; i++)
168 if (ifp->hw_addr[i] != 0)
169 break;
170
171 if (i == 6)
172 ifp->hw_addr_len = 0;
173 else
174 ifp->hw_addr_len = 6;
175 }
176 return 0;
177 }
178 #endif /* SIOCGIFHWADDR */
179
180 static int
181 if_getaddrs (void)
182 {
183 int ret;
184 struct ifaddrs *ifap;
185 struct ifaddrs *ifapfree;
186 struct interface *ifp;
187 int prefixlen;
188
189 ret = getifaddrs (&ifap);
190 if (ret != 0)
191 {
192 zlog_err ("getifaddrs(): %s", safe_strerror (errno));
193 return -1;
194 }
195
196 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
197 {
198 if (ifap->ifa_addr == NULL)
199 {
200 zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
201 __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)"));
202 continue;
203 }
204
205 ifp = if_lookup_by_name (ifap->ifa_name, VRF_DEFAULT);
206 if (ifp == NULL)
207 {
208 zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
209 ifap->ifa_name);
210 continue;
211 }
212
213 if (ifap->ifa_addr->sa_family == AF_INET)
214 {
215 struct sockaddr_in *addr;
216 struct sockaddr_in *mask;
217 struct sockaddr_in *dest;
218 struct in_addr *dest_pnt;
219 int flags = 0;
220
221 addr = (struct sockaddr_in *) ifap->ifa_addr;
222 mask = (struct sockaddr_in *) ifap->ifa_netmask;
223 prefixlen = ip_masklen (mask->sin_addr);
224
225 dest_pnt = NULL;
226
227 if (ifap->ifa_dstaddr &&
228 !IPV4_ADDR_SAME(&addr->sin_addr,
229 &((struct sockaddr_in *)
230 ifap->ifa_dstaddr)->sin_addr))
231 {
232 dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
233 dest_pnt = &dest->sin_addr;
234 flags = ZEBRA_IFA_PEER;
235 }
236 else if (ifap->ifa_broadaddr &&
237 !IPV4_ADDR_SAME(&addr->sin_addr,
238 &((struct sockaddr_in *)
239 ifap->ifa_broadaddr)->sin_addr))
240 {
241 dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
242 dest_pnt = &dest->sin_addr;
243 }
244
245 connected_add_ipv4 (ifp, flags, &addr->sin_addr,
246 prefixlen, dest_pnt, NULL);
247 }
248 if (ifap->ifa_addr->sa_family == AF_INET6)
249 {
250 struct sockaddr_in6 *addr;
251 struct sockaddr_in6 *mask;
252 struct sockaddr_in6 *dest;
253 struct in6_addr *dest_pnt;
254 int flags = 0;
255
256 addr = (struct sockaddr_in6 *) ifap->ifa_addr;
257 mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
258 prefixlen = ip6_masklen (mask->sin6_addr);
259
260 dest_pnt = NULL;
261
262 if (ifap->ifa_dstaddr &&
263 !IPV6_ADDR_SAME(&addr->sin6_addr,
264 &((struct sockaddr_in6 *)
265 ifap->ifa_dstaddr)->sin6_addr))
266 {
267 dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
268 dest_pnt = &dest->sin6_addr;
269 flags = ZEBRA_IFA_PEER;
270 }
271 else if (ifap->ifa_broadaddr &&
272 !IPV6_ADDR_SAME(&addr->sin6_addr,
273 &((struct sockaddr_in6 *)
274 ifap->ifa_broadaddr)->sin6_addr))
275 {
276 dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
277 dest_pnt = &dest->sin6_addr;
278 }
279
280 #if defined(KAME)
281 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
282 {
283 addr->sin6_scope_id =
284 ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
285 addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
286 }
287 #endif
288
289 connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen,
290 dest_pnt, NULL);
291 }
292 }
293
294 freeifaddrs (ifapfree);
295
296 return 0;
297 }
298
299 /* Fetch interface information via ioctl(). */
300 static void
301 interface_info_ioctl ()
302 {
303 struct listnode *node, *nnode;
304 struct interface *ifp;
305
306 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), node, nnode, ifp))
307 {
308 if_get_index (ifp);
309 #ifdef SIOCGIFHWADDR
310 if_get_hwaddr (ifp);
311 #endif /* SIOCGIFHWADDR */
312 if_get_flags (ifp);
313 if_get_mtu (ifp);
314 if_get_metric (ifp);
315 }
316 }
317
318 /* Lookup all interface information. */
319 void
320 interface_list (struct zebra_ns *zns)
321 {
322
323 zlog_info ("interface_list: NS %u", zns->ns_id);
324
325 /* Linux can do both proc & ioctl, ioctl is the only way to get
326 interface aliases in 2.2 series kernels. */
327 #ifdef HAVE_PROC_NET_DEV
328 interface_list_proc ();
329 #endif /* HAVE_PROC_NET_DEV */
330 interface_list_ioctl ();
331
332 /* After listing is done, get index, address, flags and other
333 interface's information. */
334 interface_info_ioctl ();
335
336 if_getaddrs ();
337
338 #if defined(HAVE_PROC_NET_IF_INET6)
339 /* Linux provides interface's IPv6 address via
340 /proc/net/if_inet6. */
341 ifaddr_proc_ipv6 ();
342 #endif /* HAVE_PROC_NET_IF_INET6 */
343 }