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