]> git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl.c
Merge pull request #2849 from patrasar/memory_leak_nht
[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 #ifdef OPEN_BSD
25
26 #include "if.h"
27 #include "sockunion.h"
28 #include "prefix.h"
29 #include "ioctl.h"
30 #include "connected.h"
31 #include "memory.h"
32 #include "zebra_memory.h"
33 #include "log.h"
34 #include "vrf.h"
35 #include "vty.h"
36 #include "lib_errors.h"
37
38 #include "zebra/interface.h"
39 #include "zebra/rib.h"
40
41 #include <ifaddrs.h>
42
43 /* Interface looking up using infamous SIOCGIFCONF. */
44 static int interface_list_ioctl(void)
45 {
46 int ret;
47 int sock;
48 #define IFNUM_BASE 32
49 int ifnum;
50 struct ifreq *ifreq;
51 struct ifconf ifconf;
52 struct interface *ifp;
53 int n;
54 int lastlen;
55
56 /* Normally SIOCGIFCONF works with AF_INET socket. */
57 sock = socket(AF_INET, SOCK_DGRAM, 0);
58 if (sock < 0) {
59 zlog_warn("Can't make AF_INET socket stream: %s",
60 safe_strerror(errno));
61 return -1;
62 }
63
64 /* Set initial ifreq count. This will be double when SIOCGIFCONF
65 fail. Solaris has SIOCGIFNUM. */
66 #ifdef SIOCGIFNUM
67 ret = ioctl(sock, SIOCGIFNUM, &ifnum);
68 if (ret < 0)
69 ifnum = IFNUM_BASE;
70 else
71 ifnum++;
72 #else
73 ifnum = IFNUM_BASE;
74 #endif /* SIOCGIFNUM */
75
76 ifconf.ifc_buf = NULL;
77
78 lastlen = 0;
79 /* Loop until SIOCGIFCONF success. */
80 for (;;) {
81 ifconf.ifc_len = sizeof(struct ifreq) * ifnum;
82 ifconf.ifc_buf =
83 XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
84
85 ret = ioctl(sock, SIOCGIFCONF, &ifconf);
86
87 if (ret < 0) {
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 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 unsigned int size;
107
108 ifreq = (struct ifreq *)((caddr_t)ifconf.ifc_req + n);
109 ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT, 0);
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 ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT, 0);
120 if_add_update(ifp);
121 ifreq++;
122 }
123 #endif /* OPEN_BSD */
124
125 end:
126 close(sock);
127 XFREE(MTYPE_TMP, ifconf.ifc_buf);
128
129 return ret;
130 }
131
132 /* Get interface's index by ioctl. */
133 static int if_get_index(struct interface *ifp)
134 {
135 if_set_index(ifp, if_nametoindex(ifp->name));
136 return ifp->ifindex;
137 }
138
139 #ifdef SIOCGIFHWADDR
140 static int if_get_hwaddr(struct interface *ifp)
141 {
142 int ret;
143 struct ifreq ifreq;
144 int i;
145
146 strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ);
147 ifreq.ifr_addr.sa_family = AF_INET;
148
149 /* Fetch Hardware address if available. */
150 ret = vrf_if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq, ifp->vrf_id);
151 if (ret < 0)
152 ifp->hw_addr_len = 0;
153 else {
154 memcpy(ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
155
156 for (i = 0; i < 6; i++)
157 if (ifp->hw_addr[i] != 0)
158 break;
159
160 if (i == 6)
161 ifp->hw_addr_len = 0;
162 else
163 ifp->hw_addr_len = 6;
164 }
165 return 0;
166 }
167 #endif /* SIOCGIFHWADDR */
168
169 static int if_getaddrs(void)
170 {
171 int ret;
172 struct ifaddrs *ifap;
173 struct ifaddrs *ifapfree;
174 struct interface *ifp;
175 int prefixlen;
176
177 ret = getifaddrs(&ifap);
178 if (ret != 0) {
179 flog_err_sys(LIB_ERR_SYSTEM_CALL, "getifaddrs(): %s",
180 safe_strerror(errno));
181 return -1;
182 }
183
184 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) {
185 if (ifap->ifa_addr == NULL) {
186 flog_err(
187 LIB_ERR_INTERFACE,
188 "%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
189 __func__,
190 (ifap->ifa_name ? ifap->ifa_name : "(null)"));
191 continue;
192 }
193
194 ifp = if_lookup_by_name(ifap->ifa_name, VRF_DEFAULT);
195 if (ifp == NULL) {
196 flog_err(LIB_ERR_INTERFACE,
197 "if_getaddrs(): Can't lookup interface %s\n",
198 ifap->ifa_name);
199 continue;
200 }
201
202 if (ifap->ifa_addr->sa_family == AF_INET) {
203 struct sockaddr_in *addr;
204 struct sockaddr_in *mask;
205 struct sockaddr_in *dest;
206 struct in_addr *dest_pnt;
207 int flags = 0;
208
209 addr = (struct sockaddr_in *)ifap->ifa_addr;
210 mask = (struct sockaddr_in *)ifap->ifa_netmask;
211 prefixlen = ip_masklen(mask->sin_addr);
212
213 dest_pnt = NULL;
214
215 if (if_is_pointopoint(ifp) && ifap->ifa_dstaddr
216 && !IPV4_ADDR_SAME(&addr->sin_addr,
217 &((struct sockaddr_in *)
218 ifap->ifa_dstaddr)
219 ->sin_addr)) {
220 dest = (struct sockaddr_in *)ifap->ifa_dstaddr;
221 dest_pnt = &dest->sin_addr;
222 flags = ZEBRA_IFA_PEER;
223 } else if (ifap->ifa_broadaddr
224 && !IPV4_ADDR_SAME(
225 &addr->sin_addr,
226 &((struct sockaddr_in *)
227 ifap->ifa_broadaddr)
228 ->sin_addr)) {
229 dest = (struct sockaddr_in *)
230 ifap->ifa_broadaddr;
231 dest_pnt = &dest->sin_addr;
232 }
233
234 connected_add_ipv4(ifp, flags, &addr->sin_addr,
235 prefixlen, dest_pnt, NULL);
236 }
237 if (ifap->ifa_addr->sa_family == AF_INET6) {
238 struct sockaddr_in6 *addr;
239 struct sockaddr_in6 *mask;
240 int flags = 0;
241
242 addr = (struct sockaddr_in6 *)ifap->ifa_addr;
243 mask = (struct sockaddr_in6 *)ifap->ifa_netmask;
244 prefixlen = ip6_masklen(mask->sin6_addr);
245
246 #if defined(KAME)
247 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
248 addr->sin6_scope_id =
249 ntohs(*(uint16_t *)&addr->sin6_addr
250 .s6_addr[2]);
251 addr->sin6_addr.s6_addr[2] =
252 addr->sin6_addr.s6_addr[3] = 0;
253 }
254 #endif
255
256 connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL,
257 prefixlen, NULL);
258 }
259 }
260
261 freeifaddrs(ifapfree);
262
263 return 0;
264 }
265
266 /* Fetch interface information via ioctl(). */
267 static void interface_info_ioctl()
268 {
269 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
270 struct interface *ifp;
271
272 FOR_ALL_INTERFACES (vrf, ifp) {
273 if_get_index(ifp);
274 #ifdef SIOCGIFHWADDR
275 if_get_hwaddr(ifp);
276 #endif /* SIOCGIFHWADDR */
277 if_get_flags(ifp);
278 if_get_mtu(ifp);
279 if_get_metric(ifp);
280 }
281 }
282
283 /* Lookup all interface information. */
284 void interface_list(struct zebra_ns *zns)
285 {
286
287 zlog_info("interface_list: NS %u", zns->ns_id);
288
289 /* Linux can do both proc & ioctl, ioctl is the only way to get
290 interface aliases in 2.2 series kernels. */
291 #ifdef HAVE_PROC_NET_DEV
292 interface_list_proc();
293 #endif /* HAVE_PROC_NET_DEV */
294 interface_list_ioctl();
295
296 /* After listing is done, get index, address, flags and other
297 interface's information. */
298 interface_info_ioctl();
299
300 if_getaddrs();
301
302 #if defined(HAVE_PROC_NET_IF_INET6)
303 /* Linux provides interface's IPv6 address via
304 /proc/net/if_inet6. */
305 ifaddr_proc_ipv6();
306 #endif /* HAVE_PROC_NET_IF_INET6 */
307 }
308
309 #endif /* OPEN_BSD */