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