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