]> git.proxmox.com Git - mirror_frr.git/blob - zebra/ioctl.c
835f1f4934c826edac851036b0889c9f6a1d7251
[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 strncpy(ifreq->ifr_name, ifp->name, IFNAMSIZ);
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;
183 struct sockaddr_in mask;
184 struct prefix_ipv4 *p;
185
186 p = (struct prefix_ipv4 *)ifc->address;
187 rib_lookup_and_pushup(p, ifp->vrf_id);
188
189 memset(&addreq, 0, sizeof addreq);
190 strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
191
192 memset(&addr, 0, sizeof(struct sockaddr_in));
193 addr.sin_addr = p->prefix;
194 addr.sin_family = p->family;
195 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
196 addr.sin_len = sizeof(struct sockaddr_in);
197 #endif
198 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
199
200 memset(&mask, 0, sizeof(struct sockaddr_in));
201 masklen2ip(p->prefixlen, &mask.sin_addr);
202 mask.sin_family = p->family;
203 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
204 mask.sin_len = sizeof(struct sockaddr_in);
205 #endif
206 memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
207
208 ret = if_ioctl(SIOCAIFADDR, (caddr_t)&addreq);
209 if (ret < 0)
210 return ret;
211 return 0;
212 }
213
214 /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
215 has ifaliasreq structure. */
216 int if_unset_prefix(struct interface *ifp, struct connected *ifc)
217 {
218 int ret;
219 struct ifaliasreq addreq;
220 struct sockaddr_in addr;
221 struct sockaddr_in mask;
222 struct prefix_ipv4 *p;
223
224 p = (struct prefix_ipv4 *)ifc->address;
225
226 memset(&addreq, 0, sizeof addreq);
227 strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
228
229 memset(&addr, 0, sizeof(struct sockaddr_in));
230 addr.sin_addr = p->prefix;
231 addr.sin_family = p->family;
232 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
233 addr.sin_len = sizeof(struct sockaddr_in);
234 #endif
235 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
236
237 memset(&mask, 0, sizeof(struct sockaddr_in));
238 masklen2ip(p->prefixlen, &mask.sin_addr);
239 mask.sin_family = p->family;
240 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
241 mask.sin_len = sizeof(struct sockaddr_in);
242 #endif
243 memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
244
245 ret = if_ioctl(SIOCDIFADDR, (caddr_t)&addreq);
246 if (ret < 0)
247 return ret;
248 return 0;
249 }
250 #else
251 /* Set up interface's address, netmask (and broadcas? ). Linux or
252 Solaris uses ifname:number semantics to set IP address aliases. */
253 int if_set_prefix(struct interface *ifp, struct connected *ifc)
254 {
255 int ret;
256 struct ifreq ifreq;
257 struct sockaddr_in addr;
258 struct sockaddr_in broad;
259 struct sockaddr_in mask;
260 struct prefix_ipv4 ifaddr;
261 struct prefix_ipv4 *p;
262
263 p = (struct prefix_ipv4 *)ifc->address;
264
265 ifaddr = *p;
266
267 ifreq_set_name(&ifreq, ifp);
268
269 addr.sin_addr = p->prefix;
270 addr.sin_family = p->family;
271 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
272 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
273 if (ret < 0)
274 return ret;
275
276 /* We need mask for make broadcast addr. */
277 masklen2ip(p->prefixlen, &mask.sin_addr);
278
279 if (if_is_broadcast(ifp)) {
280 apply_mask_ipv4(&ifaddr);
281 addr.sin_addr = ifaddr.prefix;
282
283 broad.sin_addr.s_addr =
284 (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
285 broad.sin_family = p->family;
286
287 memcpy(&ifreq.ifr_broadaddr, &broad,
288 sizeof(struct sockaddr_in));
289 ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq);
290 if (ret < 0)
291 return ret;
292 }
293
294 mask.sin_family = p->family;
295 #ifdef SUNOS_5
296 memcpy(&mask, &ifreq.ifr_addr, sizeof(mask));
297 #else
298 memcpy(&ifreq.ifr_netmask, &mask, sizeof(struct sockaddr_in));
299 #endif /* SUNOS5 */
300 ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq);
301 if (ret < 0)
302 return ret;
303
304 return 0;
305 }
306
307 /* Set up interface's address, netmask (and broadcas? ). Linux or
308 Solaris uses ifname:number semantics to set IP address aliases. */
309 int if_unset_prefix(struct interface *ifp, struct connected *ifc)
310 {
311 int ret;
312 struct ifreq ifreq;
313 struct sockaddr_in addr;
314 struct prefix_ipv4 *p;
315
316 p = (struct prefix_ipv4 *)ifc->address;
317
318 ifreq_set_name(&ifreq, ifp);
319
320 memset(&addr, 0, sizeof(struct sockaddr_in));
321 addr.sin_family = p->family;
322 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
323 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
324 if (ret < 0)
325 return ret;
326
327 return 0;
328 }
329 #endif /* HAVE_STRUCT_IFALIASREQ */
330 #endif /* HAVE_NETLINK */
331
332 /* get interface flags */
333 void if_get_flags(struct interface *ifp)
334 {
335 int ret;
336 struct ifreq ifreq;
337 #ifdef HAVE_BSD_LINK_DETECT
338 struct ifmediareq ifmr;
339 #endif /* HAVE_BSD_LINK_DETECT */
340
341 ifreq_set_name(&ifreq, ifp);
342
343 ret = if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq);
344 if (ret < 0) {
345 zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s",
346 safe_strerror(errno));
347 return;
348 }
349 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
350
351 /* Per-default, IFF_RUNNING is held high, unless link-detect says
352 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
353 * following practice on Linux and Solaris kernels
354 */
355 SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
356
357 if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) {
358 (void)memset(&ifmr, 0, sizeof(ifmr));
359 strncpy(ifmr.ifm_name, ifp->name, IFNAMSIZ);
360
361 /* Seems not all interfaces implement this ioctl */
362 if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
363 zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s",
364 safe_strerror(errno));
365 else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
366 {
367 if (ifmr.ifm_status & IFM_ACTIVE)
368 SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
369 else
370 UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
371 }
372 }
373 #endif /* HAVE_BSD_LINK_DETECT */
374
375 if_flags_update(ifp, (ifreq.ifr_flags & 0x0000ffff));
376 }
377
378 /* Set interface flags */
379 int if_set_flags(struct interface *ifp, uint64_t flags)
380 {
381 int ret;
382 struct ifreq ifreq;
383
384 memset(&ifreq, 0, sizeof(struct ifreq));
385 ifreq_set_name(&ifreq, ifp);
386
387 ifreq.ifr_flags = ifp->flags;
388 ifreq.ifr_flags |= flags;
389
390 ret = if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq);
391
392 if (ret < 0) {
393 zlog_info("can't set interface flags");
394 return ret;
395 }
396 return 0;
397 }
398
399 /* Unset interface's flag. */
400 int if_unset_flags(struct interface *ifp, uint64_t flags)
401 {
402 int ret;
403 struct ifreq ifreq;
404
405 memset(&ifreq, 0, sizeof(struct ifreq));
406 ifreq_set_name(&ifreq, ifp);
407
408 ifreq.ifr_flags = ifp->flags;
409 ifreq.ifr_flags &= ~flags;
410
411 ret = if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq);
412
413 if (ret < 0) {
414 zlog_info("can't unset interface flags");
415 return ret;
416 }
417 return 0;
418 }
419
420 #ifdef LINUX_IPV6
421 #ifndef _LINUX_IN6_H
422 /* linux/include/net/ipv6.h */
423 struct in6_ifreq {
424 struct in6_addr ifr6_addr;
425 u_int32_t ifr6_prefixlen;
426 int ifr6_ifindex;
427 };
428 #endif /* _LINUX_IN6_H */
429
430 /* Interface's address add/delete functions. */
431 int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
432 {
433 int ret;
434 struct prefix_ipv6 *p;
435 struct in6_ifreq ifreq;
436
437 p = (struct prefix_ipv6 *)ifc->address;
438
439 memset(&ifreq, 0, sizeof(struct in6_ifreq));
440
441 memcpy(&ifreq.ifr6_addr, &p->prefix, sizeof(struct in6_addr));
442 ifreq.ifr6_ifindex = ifp->ifindex;
443 ifreq.ifr6_prefixlen = p->prefixlen;
444
445 ret = if_ioctl_ipv6(SIOCSIFADDR, (caddr_t)&ifreq);
446
447 return ret;
448 }
449
450 int if_prefix_delete_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(SIOCDIFADDR, (caddr_t)&ifreq);
465
466 return ret;
467 }
468 #else /* LINUX_IPV6 */
469 #ifdef HAVE_STRUCT_IN6_ALIASREQ
470 #ifndef ND6_INFINITE_LIFETIME
471 #define ND6_INFINITE_LIFETIME 0xffffffffL
472 #endif /* ND6_INFINITE_LIFETIME */
473 int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
474 {
475 int ret;
476 struct in6_aliasreq addreq;
477 struct sockaddr_in6 addr;
478 struct sockaddr_in6 mask;
479 struct prefix_ipv6 *p;
480
481 p = (struct prefix_ipv6 *)ifc->address;
482
483 memset(&addreq, 0, sizeof addreq);
484 strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
485
486 memset(&addr, 0, sizeof(struct sockaddr_in6));
487 addr.sin6_addr = p->prefix;
488 addr.sin6_family = p->family;
489 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
490 addr.sin6_len = sizeof(struct sockaddr_in6);
491 #endif
492 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
493
494 memset(&mask, 0, sizeof(struct sockaddr_in6));
495 masklen2ip6(p->prefixlen, &mask.sin6_addr);
496 mask.sin6_family = p->family;
497 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
498 mask.sin6_len = sizeof(struct sockaddr_in6);
499 #endif
500 memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
501
502 addreq.ifra_lifetime.ia6t_vltime = 0xffffffff;
503 addreq.ifra_lifetime.ia6t_pltime = 0xffffffff;
504
505 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
506 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
507 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
508 #endif
509
510 ret = if_ioctl_ipv6(SIOCAIFADDR_IN6, (caddr_t)&addreq);
511 if (ret < 0)
512 return ret;
513 return 0;
514 }
515
516 int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
517 {
518 int ret;
519 struct in6_aliasreq addreq;
520 struct sockaddr_in6 addr;
521 struct sockaddr_in6 mask;
522 struct prefix_ipv6 *p;
523
524 p = (struct prefix_ipv6 *)ifc->address;
525
526 memset(&addreq, 0, sizeof addreq);
527 strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
528
529 memset(&addr, 0, sizeof(struct sockaddr_in6));
530 addr.sin6_addr = p->prefix;
531 addr.sin6_family = p->family;
532 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
533 addr.sin6_len = sizeof(struct sockaddr_in6);
534 #endif
535 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
536
537 memset(&mask, 0, sizeof(struct sockaddr_in6));
538 masklen2ip6(p->prefixlen, &mask.sin6_addr);
539 mask.sin6_family = p->family;
540 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
541 mask.sin6_len = sizeof(struct sockaddr_in6);
542 #endif
543 memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
544
545 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
546 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
547 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
548 #endif
549
550 ret = if_ioctl_ipv6(SIOCDIFADDR_IN6, (caddr_t)&addreq);
551 if (ret < 0)
552 return ret;
553 return 0;
554 }
555 #else
556 int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
557 {
558 return 0;
559 }
560
561 int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
562 {
563 return 0;
564 }
565 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
566
567 #endif /* LINUX_IPV6 */
568
569 #endif /* !SUNOS_5 */