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