www.usr.com/support/gpl/USR9108_release1.5.tar.gz
[bcm963xx.git] / userapps / opensource / zebra / 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 #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
30 #include "zebra/rib.h"
31 #include "zebra/rt.h"
32
33 /* clear and set interface name string */
34 void
35 ifreq_set_name (struct ifreq *ifreq, struct interface *ifp)
36 {
37   strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ);
38 }
39
40 /* call ioctl system call */
41 int
42 if_ioctl (u_long request, caddr_t buffer)
43 {
44   int sock;
45   int ret = 0;
46   int err = 0;
47
48   sock = socket (AF_INET, SOCK_DGRAM, 0);
49   if (sock < 0)
50     {
51       perror ("socket");
52       exit (1);
53     }
54
55   ret = ioctl (sock, request, buffer);
56   if (ret < 0)
57     {
58       err = errno;
59     }
60   close (sock);
61   
62   if (ret < 0) 
63     {
64       errno = err;
65       return ret;
66     }
67   return 0;
68 }
69
70 #ifdef HAVE_IPV6
71 int
72 if_ioctl_ipv6 (u_long request, caddr_t buffer)
73 {
74   int sock;
75   int ret = 0;
76   int err = 0;
77
78   sock = socket (AF_INET6, SOCK_DGRAM, 0);
79   if (sock < 0)
80     {
81       perror ("socket");
82       exit (1);
83     }
84
85   ret = ioctl (sock, request, buffer);
86   if (ret < 0)
87     {
88       err = errno;
89     }
90   close (sock);
91   
92   if (ret < 0) 
93     {
94       errno = err;
95       return ret;
96     }
97   return 0;
98 }
99 #endif /* HAVE_IPV6 */
100
101 #ifdef BRCM_CMD_SUPPORT
102 /*
103  * get interface metric
104  *   -- if value is not avaliable set -1
105  */
106 void
107 if_get_metric (struct interface *ifp)
108 {
109 #ifdef SIOCGIFMETRIC
110   struct ifreq ifreq;
111
112   ifreq_set_name (&ifreq, ifp);
113
114   if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0) 
115     return;
116   ifp->metric = ifreq.ifr_metric;
117   if (ifp->metric == 0)
118     ifp->metric = 1;
119 #else /* SIOCGIFMETRIC */
120   ifp->metric = -1;
121 #endif /* SIOCGIFMETRIC */
122 }
123
124 /* get interface MTU */
125 void
126 if_get_mtu (struct interface *ifp)
127 {
128   struct ifreq ifreq;
129
130   ifreq_set_name (&ifreq, ifp);
131
132 #if defined(SIOCGIFMTU)
133   if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0) 
134     {
135 #ifdef BRCM_RIP_DEBUG
136       zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
137 #endif
138       ifp->mtu = -1;
139       return;
140     }
141
142 #ifdef SUNOS_5
143   ifp->mtu = ifreq.ifr_metric;
144 #else
145   ifp->mtu = ifreq.ifr_mtu;
146 #endif /* SUNOS_5 */
147
148 #else
149 #ifdef BRCM_RIP_DEBUG
150   zlog (NULL, LOG_INFO, "Can't lookup mtu on this system");
151 #endif
152   ifp->mtu = -1;
153 #endif
154 }
155 #endif /* BRCM_CMD_SUPPORT */
156
157 #ifdef HAVE_NETLINK
158 /* Interface address setting via netlink interface. */
159 int
160 if_set_prefix (struct interface *ifp, struct connected *ifc)
161 {
162   return kernel_address_add_ipv4 (ifp, ifc);
163 }
164
165 /* Interface address is removed using netlink interface. */
166 int
167 if_unset_prefix (struct interface *ifp, struct connected *ifc)
168 {
169   return kernel_address_delete_ipv4 (ifp, ifc);
170 }
171 #else /* ! HAVE_NETLINK */
172 #ifdef HAVE_IFALIASREQ
173 /* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
174    has ifaliasreq structure.  */
175 int
176 if_set_prefix (struct interface *ifp, struct connected *ifc)
177 {
178   int ret;
179   struct ifaliasreq addreq;
180   struct sockaddr_in addr;
181   struct sockaddr_in mask;
182   struct prefix_ipv4 *p;
183
184   p = (struct prefix_ipv4 *) ifc->address;
185
186   memset (&addreq, 0, sizeof addreq);
187   strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
188
189   memset (&addr, 0, sizeof (struct sockaddr_in));
190   addr.sin_addr = p->prefix;
191   addr.sin_family = p->family;
192 #ifdef HAVE_SIN_LEN
193   addr.sin_len = sizeof (struct sockaddr_in);
194 #endif
195   memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
196
197   memset (&mask, 0, sizeof (struct sockaddr_in));
198   masklen2ip (p->prefixlen, &mask.sin_addr);
199   mask.sin_family = p->family;
200 #ifdef HAVE_SIN_LEN
201   mask.sin_len = sizeof (struct sockaddr_in);
202 #endif
203   memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
204   
205   ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq);
206   if (ret < 0)
207     return ret;
208   return 0;
209 }
210
211 /* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
212    has ifaliasreq structure.  */
213 int
214 if_unset_prefix (struct interface *ifp, struct connected *ifc)
215 {
216   int ret;
217   struct ifaliasreq addreq;
218   struct sockaddr_in addr;
219   struct sockaddr_in mask;
220   struct prefix_ipv4 *p;
221
222   p = (struct prefix_ipv4 *)ifc->address;
223
224   memset (&addreq, 0, sizeof addreq);
225   strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
226
227   memset (&addr, 0, sizeof (struct sockaddr_in));
228   addr.sin_addr = p->prefix;
229   addr.sin_family = p->family;
230 #ifdef HAVE_SIN_LEN
231   addr.sin_len = sizeof (struct sockaddr_in);
232 #endif
233   memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
234
235   memset (&mask, 0, sizeof (struct sockaddr_in));
236   masklen2ip (p->prefixlen, &mask.sin_addr);
237   mask.sin_family = p->family;
238 #ifdef HAVE_SIN_LEN
239   mask.sin_len = sizeof (struct sockaddr_in);
240 #endif
241   memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
242   
243   ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq);
244   if (ret < 0)
245     return ret;
246   return 0;
247 }
248 #else
249 /* Set up interface's address, netmask (and broadcas? ).  Linux or
250    Solaris uses ifname:number semantics to set IP address aliases. */
251 int
252 if_set_prefix (struct interface *ifp, struct connected *ifc)
253 {
254   int ret;
255   struct ifreq ifreq;
256   struct sockaddr_in addr;
257   struct sockaddr_in broad;
258   struct sockaddr_in mask;
259   struct prefix_ipv4 ifaddr;
260   struct prefix_ipv4 *p;
261
262   p = (struct prefix_ipv4 *) ifc->address;
263
264   ifaddr = *p;
265
266   ifreq_set_name (&ifreq, ifp);
267
268   addr.sin_addr = p->prefix;
269   addr.sin_family = p->family;
270   memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
271   ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
272   if (ret < 0)
273     return ret;
274   
275   /* We need mask for make broadcast addr. */
276   masklen2ip (p->prefixlen, &mask.sin_addr);
277
278   if (if_is_broadcast (ifp))
279     {
280       apply_mask_ipv4 (&ifaddr);
281       addr.sin_addr = ifaddr.prefix;
282
283       broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
284       broad.sin_family = p->family;
285
286       memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in));
287       ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq);
288       if (ret < 0)
289         return ret;
290     }
291
292   mask.sin_family = p->family;
293 #ifdef SUNOS_5
294   memcpy (&mask, &ifreq.ifr_addr, sizeof (mask));
295 #else
296   memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in));
297 #endif /* SUNOS5 */
298   ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq);
299   if (ret < 0)
300     return ret;
301
302   return 0;
303 }
304
305 /* Set up interface's address, netmask (and broadcas? ).  Linux or
306    Solaris uses ifname:number semantics to set IP address aliases. */
307 int
308 if_unset_prefix (struct interface *ifp, struct connected *ifc)
309 {
310   int ret;
311   struct ifreq ifreq;
312   struct sockaddr_in addr;
313   struct prefix_ipv4 *p;
314
315   p = (struct prefix_ipv4 *) ifc->address;
316
317   ifreq_set_name (&ifreq, ifp);
318
319   memset (&addr, 0, sizeof (struct sockaddr_in));
320   addr.sin_family = p->family;
321   memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
322   ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
323   if (ret < 0)
324     return ret;
325
326   return 0;
327 }
328 #endif /* HAVE_IFALIASREQ */
329 #endif /* HAVE_NETLINK */
330
331 /* get interface flags */
332 void
333 if_get_flags (struct interface *ifp)
334 {
335   int ret;
336   struct ifreq ifreq;
337
338   ifreq_set_name (&ifreq, ifp);
339
340   ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq);
341   if (ret < 0) 
342     {
343       perror ("ioctl");
344       return;
345     }
346
347   ifp->flags = ifreq.ifr_flags & 0x0000ffff;
348 }
349
350 /* Set interface flags */
351 int
352 if_set_flags (struct interface *ifp, unsigned long flags)
353 {
354   int ret;
355   struct ifreq ifreq;
356
357   ifreq_set_name (&ifreq, ifp);
358
359   ifreq.ifr_flags = ifp->flags;
360   ifreq.ifr_flags |= flags;
361
362   ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
363
364   if (ret < 0)
365     {
366 #ifdef BRCM_RIP_DEBUG
367       zlog_info ("can't set interface flags");
368 #endif
369       return ret;
370     }
371   return 0;
372 }
373
374 /* Unset interface's flag. */
375 int
376 if_unset_flags (struct interface *ifp, unsigned long flags)
377 {
378   int ret;
379   struct ifreq ifreq;
380
381   ifreq_set_name (&ifreq, ifp);
382
383   ifreq.ifr_flags = ifp->flags;
384   ifreq.ifr_flags &= ~flags;
385
386   ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
387
388   if (ret < 0)
389     {
390 #ifdef BRCM_RIP_DEBUG
391       zlog_info ("can't unset interface flags");
392 #endif
393       return ret;
394     }
395   return 0;
396 }
397
398 #ifdef HAVE_IPV6
399
400 #ifdef LINUX_IPV6
401 #ifndef _LINUX_IN6_H
402 /* linux/include/net/ipv6.h */
403 struct in6_ifreq 
404 {
405   struct in6_addr ifr6_addr;
406   u_int32_t ifr6_prefixlen;
407   int ifr6_ifindex;
408 };
409 #endif /* _LINUX_IN6_H */
410
411 /* Interface's address add/delete functions. */
412 int
413 if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
414 {
415   int ret;
416   struct prefix_ipv6 *p;
417   struct in6_ifreq ifreq;
418
419   p = (struct prefix_ipv6 *) ifc->address;
420
421   memset (&ifreq, 0, sizeof (struct in6_ifreq));
422
423   memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
424   ifreq.ifr6_ifindex = ifp->ifindex;
425   ifreq.ifr6_prefixlen = p->prefixlen;
426
427   ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq);
428
429   return ret;
430 }
431
432 int
433 if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
434 {
435   int ret;
436   struct prefix_ipv6 *p;
437   struct in6_ifreq ifreq;
438
439   p = (struct prefix_ipv6 *) ifc->address;
440
441   memset (&ifreq, 0, sizeof (struct in6_ifreq));
442
443   memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
444   ifreq.ifr6_ifindex = ifp->ifindex;
445   ifreq.ifr6_prefixlen = p->prefixlen;
446
447   ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq);
448
449   return ret;
450 }
451 #else /* LINUX_IPV6 */
452 #ifdef HAVE_IN6_ALIASREQ
453 #ifndef ND6_INFINITE_LIFETIME
454 #define ND6_INFINITE_LIFETIME 0xffffffffL
455 #endif /* ND6_INFINITE_LIFETIME */
456 int
457 if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
458 {
459   int ret;
460   struct in6_aliasreq addreq;
461   struct sockaddr_in6 addr;
462   struct sockaddr_in6 mask;
463   struct prefix_ipv6 *p;
464
465   p = (struct prefix_ipv6 * ) ifc->address;
466
467   memset (&addreq, 0, sizeof addreq);
468   strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
469
470   memset (&addr, 0, sizeof (struct sockaddr_in6));
471   addr.sin6_addr = p->prefix;
472   addr.sin6_family = p->family;
473 #ifdef HAVE_SIN_LEN
474   addr.sin6_len = sizeof (struct sockaddr_in6);
475 #endif
476   memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
477
478   memset (&mask, 0, sizeof (struct sockaddr_in6));
479   masklen2ip6 (p->prefixlen, &mask.sin6_addr);
480   mask.sin6_family = p->family;
481 #ifdef HAVE_SIN_LEN
482   mask.sin6_len = sizeof (struct sockaddr_in6);
483 #endif
484   memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
485   
486   addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 
487   addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 
488
489   ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq);
490   if (ret < 0)
491     return ret;
492   return 0;
493 }
494
495 int
496 if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
497 {
498   int ret;
499   struct in6_aliasreq addreq;
500   struct sockaddr_in6 addr;
501   struct sockaddr_in6 mask;
502   struct prefix_ipv6 *p;
503
504   p = (struct prefix_ipv6 *) ifc->address;
505
506   memset (&addreq, 0, sizeof addreq);
507   strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
508
509   memset (&addr, 0, sizeof (struct sockaddr_in6));
510   addr.sin6_addr = p->prefix;
511   addr.sin6_family = p->family;
512 #ifdef HAVE_SIN_LEN
513   addr.sin6_len = sizeof (struct sockaddr_in6);
514 #endif
515   memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
516
517   memset (&mask, 0, sizeof (struct sockaddr_in6));
518   masklen2ip6 (p->prefixlen, &mask.sin6_addr);
519   mask.sin6_family = p->family;
520 #ifdef HAVE_SIN_LEN
521   mask.sin6_len = sizeof (struct sockaddr_in6);
522 #endif
523   memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
524
525   addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 
526   addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 
527
528   ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq);
529   if (ret < 0)
530     return ret;
531   return 0;
532 }
533 #else
534 int
535 if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
536 {
537   return 0;
538 }
539
540 int
541 if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
542 {
543   return 0;
544 }
545 #endif /* HAVE_IN6_ALIASREQ */
546
547 #endif /* LINUX_IPV6 */
548
549 #endif /* HAVE_IPV6 */