blob: e28d359efb0b0ff3aab6898899b9ab89102bbca3 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "linklist.h"
26#include "if.h"
27#include "prefix.h"
28#include "ioctl.h"
29#include "log.h"
pauledd7c242003-06-04 13:59:38 +000030#include "privs.h"
paul718e3742002-12-13 20:15:29 +000031
32#include "zebra/rib.h"
33#include "zebra/rt.h"
34
pauledd7c242003-06-04 13:59:38 +000035extern struct zebra_privs_t zserv_privs;
36
paul718e3742002-12-13 20:15:29 +000037/* clear and set interface name string */
38void
39ifreq_set_name (struct ifreq *ifreq, struct interface *ifp)
40{
41 strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ);
42}
43
44/* call ioctl system call */
45int
46if_ioctl (u_long request, caddr_t buffer)
47{
48 int sock;
ajs4460e7a2005-01-29 17:07:40 +000049 int ret;
50 int err;
paul718e3742002-12-13 20:15:29 +000051
pauledd7c242003-06-04 13:59:38 +000052 if (zserv_privs.change(ZPRIVS_RAISE))
53 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +000054 sock = socket (AF_INET, SOCK_DGRAM, 0);
55 if (sock < 0)
56 {
pauledd7c242003-06-04 13:59:38 +000057 if (zserv_privs.change(ZPRIVS_LOWER))
58 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +000059 perror ("socket");
60 exit (1);
61 }
ajs4460e7a2005-01-29 17:07:40 +000062 if ((ret = ioctl (sock, request, buffer)) < 0)
63 err = errno;
pauledd7c242003-06-04 13:59:38 +000064 if (zserv_privs.change(ZPRIVS_LOWER))
65 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +000066 close (sock);
67
68 if (ret < 0)
69 {
70 errno = err;
71 return ret;
72 }
73 return 0;
74}
75
76#ifdef HAVE_IPV6
77int
78if_ioctl_ipv6 (u_long request, caddr_t buffer)
79{
80 int sock;
ajs4460e7a2005-01-29 17:07:40 +000081 int ret;
82 int err;
paul718e3742002-12-13 20:15:29 +000083
pauledd7c242003-06-04 13:59:38 +000084 if (zserv_privs.change(ZPRIVS_RAISE))
85 zlog (NULL, LOG_ERR, "Can't raise privileges");
paul718e3742002-12-13 20:15:29 +000086 sock = socket (AF_INET6, SOCK_DGRAM, 0);
87 if (sock < 0)
88 {
pauledd7c242003-06-04 13:59:38 +000089 if (zserv_privs.change(ZPRIVS_LOWER))
90 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +000091 perror ("socket");
92 exit (1);
93 }
94
ajs4460e7a2005-01-29 17:07:40 +000095 if ((ret = ioctl (sock, request, buffer)) < 0)
96 err = errno;
pauledd7c242003-06-04 13:59:38 +000097 if (zserv_privs.change(ZPRIVS_LOWER))
98 zlog (NULL, LOG_ERR, "Can't lower privileges");
paul718e3742002-12-13 20:15:29 +000099 close (sock);
100
101 if (ret < 0)
102 {
103 errno = err;
104 return ret;
105 }
106 return 0;
107}
108#endif /* HAVE_IPV6 */
109
110/*
111 * get interface metric
112 * -- if value is not avaliable set -1
113 */
114void
115if_get_metric (struct interface *ifp)
116{
117#ifdef SIOCGIFMETRIC
118 struct ifreq ifreq;
119
120 ifreq_set_name (&ifreq, ifp);
121
122 if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0)
123 return;
124 ifp->metric = ifreq.ifr_metric;
125 if (ifp->metric == 0)
126 ifp->metric = 1;
127#else /* SIOCGIFMETRIC */
128 ifp->metric = -1;
129#endif /* SIOCGIFMETRIC */
130}
131
132/* get interface MTU */
133void
134if_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 {
143 zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
paul44145db2004-05-09 11:00:23 +0000144 ifp->mtu6 = ifp->mtu = -1;
paul718e3742002-12-13 20:15:29 +0000145 return;
146 }
147
148#ifdef SUNOS_5
paul44145db2004-05-09 11:00:23 +0000149 ifp->mtu6 = ifp->mtu = ifreq.ifr_metric;
paul718e3742002-12-13 20:15:29 +0000150#else
paul44145db2004-05-09 11:00:23 +0000151 ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu;
paul718e3742002-12-13 20:15:29 +0000152#endif /* SUNOS_5 */
153
154#else
155 zlog (NULL, LOG_INFO, "Can't lookup mtu on this system");
paul44145db2004-05-09 11:00:23 +0000156 ifp->mtu6 = ifp->mtu = -1;
paul718e3742002-12-13 20:15:29 +0000157#endif
158}
159
160#ifdef HAVE_NETLINK
161/* Interface address setting via netlink interface. */
162int
163if_set_prefix (struct interface *ifp, struct connected *ifc)
164{
165 return kernel_address_add_ipv4 (ifp, ifc);
166}
167
168/* Interface address is removed using netlink interface. */
169int
170if_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_IFALIASREQ
176/* Set up interface's IP address, netmask (and broadcas? ). *BSD may
177 has ifaliasreq structure. */
178int
179if_set_prefix (struct interface *ifp, struct connected *ifc)
180{
181 int ret;
182 struct ifaliasreq addreq;
183 struct sockaddr_in addr;
184 struct sockaddr_in mask;
185 struct prefix_ipv4 *p;
186
187 p = (struct prefix_ipv4 *) ifc->address;
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_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_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. */
216int
217if_unset_prefix (struct interface *ifp, struct connected *ifc)
218{
219 int ret;
220 struct ifaliasreq addreq;
221 struct sockaddr_in addr;
222 struct sockaddr_in mask;
223 struct prefix_ipv4 *p;
224
225 p = (struct prefix_ipv4 *)ifc->address;
226
227 memset (&addreq, 0, sizeof addreq);
228 strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
229
230 memset (&addr, 0, sizeof (struct sockaddr_in));
231 addr.sin_addr = p->prefix;
232 addr.sin_family = p->family;
233#ifdef HAVE_SIN_LEN
234 addr.sin_len = sizeof (struct sockaddr_in);
235#endif
236 memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
237
238 memset (&mask, 0, sizeof (struct sockaddr_in));
239 masklen2ip (p->prefixlen, &mask.sin_addr);
240 mask.sin_family = p->family;
241#ifdef HAVE_SIN_LEN
242 mask.sin_len = sizeof (struct sockaddr_in);
243#endif
244 memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
245
246 ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq);
247 if (ret < 0)
248 return ret;
249 return 0;
250}
251#else
252/* Set up interface's address, netmask (and broadcas? ). Linux or
253 Solaris uses ifname:number semantics to set IP address aliases. */
254int
255if_set_prefix (struct interface *ifp, struct connected *ifc)
256{
257 int ret;
258 struct ifreq ifreq;
259 struct sockaddr_in addr;
260 struct sockaddr_in broad;
261 struct sockaddr_in mask;
262 struct prefix_ipv4 ifaddr;
263 struct prefix_ipv4 *p;
264
265 p = (struct prefix_ipv4 *) ifc->address;
266
267 ifaddr = *p;
268
269 ifreq_set_name (&ifreq, ifp);
270
271 addr.sin_addr = p->prefix;
272 addr.sin_family = p->family;
273 memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
274 ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
275 if (ret < 0)
276 return ret;
277
278 /* We need mask for make broadcast addr. */
279 masklen2ip (p->prefixlen, &mask.sin_addr);
280
281 if (if_is_broadcast (ifp))
282 {
283 apply_mask_ipv4 (&ifaddr);
284 addr.sin_addr = ifaddr.prefix;
285
286 broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
287 broad.sin_family = p->family;
288
289 memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in));
290 ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq);
291 if (ret < 0)
292 return ret;
293 }
294
295 mask.sin_family = p->family;
296#ifdef SUNOS_5
297 memcpy (&mask, &ifreq.ifr_addr, sizeof (mask));
298#else
299 memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in));
300#endif /* SUNOS5 */
301 ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq);
302 if (ret < 0)
303 return ret;
304
305 return 0;
306}
307
308/* Set up interface's address, netmask (and broadcas? ). Linux or
309 Solaris uses ifname:number semantics to set IP address aliases. */
310int
311if_unset_prefix (struct interface *ifp, struct connected *ifc)
312{
313 int ret;
314 struct ifreq ifreq;
315 struct sockaddr_in addr;
316 struct prefix_ipv4 *p;
317
318 p = (struct prefix_ipv4 *) ifc->address;
319
320 ifreq_set_name (&ifreq, ifp);
321
322 memset (&addr, 0, sizeof (struct sockaddr_in));
323 addr.sin_family = p->family;
324 memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
325 ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
326 if (ret < 0)
327 return ret;
328
329 return 0;
330}
331#endif /* HAVE_IFALIASREQ */
332#endif /* HAVE_NETLINK */
333
334/* get interface flags */
335void
336if_get_flags (struct interface *ifp)
337{
338 int ret;
339 struct ifreq ifreq;
340
341 ifreq_set_name (&ifreq, ifp);
342
343 ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq);
344 if (ret < 0)
345 {
346 perror ("ioctl");
347 return;
348 }
349
350 ifp->flags = ifreq.ifr_flags & 0x0000ffff;
351}
352
353/* Set interface flags */
354int
355if_set_flags (struct interface *ifp, unsigned long flags)
356{
357 int ret;
358 struct ifreq ifreq;
359
pauld1724b62003-10-22 02:41:52 +0000360 memset (&ifreq, 0, sizeof(struct ifreq));
paul718e3742002-12-13 20:15:29 +0000361 ifreq_set_name (&ifreq, ifp);
362
363 ifreq.ifr_flags = ifp->flags;
364 ifreq.ifr_flags |= flags;
365
366 ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
367
368 if (ret < 0)
369 {
370 zlog_info ("can't set interface flags");
371 return ret;
372 }
373 return 0;
374}
375
376/* Unset interface's flag. */
377int
378if_unset_flags (struct interface *ifp, unsigned long flags)
379{
380 int ret;
381 struct ifreq ifreq;
382
pauld1724b62003-10-22 02:41:52 +0000383 memset (&ifreq, 0, sizeof(struct ifreq));
paul718e3742002-12-13 20:15:29 +0000384 ifreq_set_name (&ifreq, ifp);
385
386 ifreq.ifr_flags = ifp->flags;
387 ifreq.ifr_flags &= ~flags;
388
389 ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
390
391 if (ret < 0)
392 {
393 zlog_info ("can't unset interface flags");
394 return ret;
395 }
396 return 0;
397}
398
399#ifdef HAVE_IPV6
400
401#ifdef LINUX_IPV6
402#ifndef _LINUX_IN6_H
403/* linux/include/net/ipv6.h */
404struct in6_ifreq
405{
406 struct in6_addr ifr6_addr;
407 u_int32_t ifr6_prefixlen;
408 int ifr6_ifindex;
409};
410#endif /* _LINUX_IN6_H */
411
412/* Interface's address add/delete functions. */
413int
414if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
415{
416 int ret;
417 struct prefix_ipv6 *p;
418 struct in6_ifreq ifreq;
419
420 p = (struct prefix_ipv6 *) ifc->address;
421
422 memset (&ifreq, 0, sizeof (struct in6_ifreq));
423
424 memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
425 ifreq.ifr6_ifindex = ifp->ifindex;
426 ifreq.ifr6_prefixlen = p->prefixlen;
427
428 ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq);
429
430 return ret;
431}
432
433int
434if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
435{
436 int ret;
437 struct prefix_ipv6 *p;
438 struct in6_ifreq ifreq;
439
440 p = (struct prefix_ipv6 *) ifc->address;
441
442 memset (&ifreq, 0, sizeof (struct in6_ifreq));
443
444 memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
445 ifreq.ifr6_ifindex = ifp->ifindex;
446 ifreq.ifr6_prefixlen = p->prefixlen;
447
448 ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq);
449
450 return ret;
451}
452#else /* LINUX_IPV6 */
453#ifdef HAVE_IN6_ALIASREQ
454#ifndef ND6_INFINITE_LIFETIME
455#define ND6_INFINITE_LIFETIME 0xffffffffL
456#endif /* ND6_INFINITE_LIFETIME */
457int
458if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
459{
460 int ret;
461 struct in6_aliasreq addreq;
462 struct sockaddr_in6 addr;
463 struct sockaddr_in6 mask;
464 struct prefix_ipv6 *p;
465
466 p = (struct prefix_ipv6 * ) ifc->address;
467
468 memset (&addreq, 0, sizeof addreq);
469 strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
470
471 memset (&addr, 0, sizeof (struct sockaddr_in6));
472 addr.sin6_addr = p->prefix;
473 addr.sin6_family = p->family;
474#ifdef HAVE_SIN_LEN
475 addr.sin6_len = sizeof (struct sockaddr_in6);
476#endif
477 memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
478
479 memset (&mask, 0, sizeof (struct sockaddr_in6));
480 masklen2ip6 (p->prefixlen, &mask.sin6_addr);
481 mask.sin6_family = p->family;
482#ifdef HAVE_SIN_LEN
483 mask.sin6_len = sizeof (struct sockaddr_in6);
484#endif
485 memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
paul0e4f1902003-06-12 02:13:45 +0000486
487 addreq.ifra_lifetime.ia6t_vltime = 0xffffffff;
488 addreq.ifra_lifetime.ia6t_pltime = 0xffffffff;
paul718e3742002-12-13 20:15:29 +0000489
hasso726f9b22003-05-25 21:04:54 +0000490#ifdef HAVE_IFRA_LIFETIME
paul718e3742002-12-13 20:15:29 +0000491 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
492 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
hasso726f9b22003-05-25 21:04:54 +0000493#endif
paul718e3742002-12-13 20:15:29 +0000494
495 ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq);
496 if (ret < 0)
497 return ret;
498 return 0;
499}
500
501int
502if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
503{
504 int ret;
505 struct in6_aliasreq addreq;
506 struct sockaddr_in6 addr;
507 struct sockaddr_in6 mask;
508 struct prefix_ipv6 *p;
509
510 p = (struct prefix_ipv6 *) ifc->address;
511
512 memset (&addreq, 0, sizeof addreq);
513 strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
514
515 memset (&addr, 0, sizeof (struct sockaddr_in6));
516 addr.sin6_addr = p->prefix;
517 addr.sin6_family = p->family;
518#ifdef HAVE_SIN_LEN
519 addr.sin6_len = sizeof (struct sockaddr_in6);
520#endif
521 memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
522
523 memset (&mask, 0, sizeof (struct sockaddr_in6));
524 masklen2ip6 (p->prefixlen, &mask.sin6_addr);
525 mask.sin6_family = p->family;
526#ifdef HAVE_SIN_LEN
527 mask.sin6_len = sizeof (struct sockaddr_in6);
528#endif
529 memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
530
hasso726f9b22003-05-25 21:04:54 +0000531#ifdef HAVE_IFRA_LIFETIME
paul718e3742002-12-13 20:15:29 +0000532 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
533 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
hasso726f9b22003-05-25 21:04:54 +0000534#endif
paul718e3742002-12-13 20:15:29 +0000535
536 ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq);
537 if (ret < 0)
538 return ret;
539 return 0;
540}
541#else
542int
543if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
544{
545 return 0;
546}
547
548int
549if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
550{
551 return 0;
552}
553#endif /* HAVE_IN6_ALIASREQ */
554
555#endif /* LINUX_IPV6 */
556
557#endif /* HAVE_IPV6 */