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