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
31#include "zebra/rib.h"
32#include "zebra/rt.h"
33
34/* clear and set interface name string */
35void
36ifreq_set_name (struct ifreq *ifreq, struct interface *ifp)
37{
38  strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ);
39}
40
41/* call ioctl system call */
42int
43if_ioctl (u_long request, caddr_t buffer)
44{
45  int sock;
46  int ret = 0;
47  int err = 0;
48
49  sock = socket (AF_INET, SOCK_DGRAM, 0);
50  if (sock < 0)
51    {
52      perror ("socket");
53      exit (1);
54    }
55
56  ret = ioctl (sock, request, buffer);
57  if (ret < 0)
58    {
59      err = errno;
60    }
61  close (sock);
62
63  if (ret < 0)
64    {
65      errno = err;
66      return ret;
67    }
68  return 0;
69}
70
71#ifdef HAVE_IPV6
72int
73if_ioctl_ipv6 (u_long request, caddr_t buffer)
74{
75  int sock;
76  int ret = 0;
77  int err = 0;
78
79  sock = socket (AF_INET6, SOCK_DGRAM, 0);
80  if (sock < 0)
81    {
82      perror ("socket");
83      exit (1);
84    }
85
86  ret = ioctl (sock, request, buffer);
87  if (ret < 0)
88    {
89      err = errno;
90    }
91  close (sock);
92
93  if (ret < 0)
94    {
95      errno = err;
96      return ret;
97    }
98  return 0;
99}
100#endif /* HAVE_IPV6 */
101
102#ifdef FOX_CMD_SUPPORT
103/*
104 * get interface metric
105 *   -- if value is not avaliable set -1
106 */
107void
108if_get_metric (struct interface *ifp)
109{
110#ifdef SIOCGIFMETRIC
111  struct ifreq ifreq;
112
113  ifreq_set_name (&ifreq, ifp);
114
115  if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0)
116    return;
117  ifp->metric = ifreq.ifr_metric;
118  if (ifp->metric == 0)
119    ifp->metric = 1;
120#else /* SIOCGIFMETRIC */
121  ifp->metric = -1;
122#endif /* SIOCGIFMETRIC */
123}
124
125/* get interface MTU */
126void
127if_get_mtu (struct interface *ifp)
128{
129  struct ifreq ifreq;
130
131  ifreq_set_name (&ifreq, ifp);
132
133#if defined(SIOCGIFMTU)
134  if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0)
135    {
136#ifdef FOX_RIP_DEBUG
137      zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
138#endif /* FOX_RIP_DEBUG */
139      ifp->mtu = -1;
140      return;
141    }
142
143#ifdef SUNOS_5
144  ifp->mtu = ifreq.ifr_metric;
145#else
146  ifp->mtu = ifreq.ifr_mtu;
147#endif /* SUNOS_5 */
148
149#else
150#ifdef FOX_RIP_DEBUG
151  zlog (NULL, LOG_INFO, "Can't lookup mtu on this system");
152#endif /* FOX_RIP_DEBUG */
153  ifp->mtu = -1;
154#endif
155}
156#endif /* FOX_CMD_SUPPORT */
157
158#ifdef HAVE_NETLINK
159/* Interface address setting via netlink interface. */
160int
161if_set_prefix (struct interface *ifp, struct connected *ifc)
162{
163  return kernel_address_add_ipv4 (ifp, ifc);
164}
165
166/* Interface address is removed using netlink interface. */
167int
168if_unset_prefix (struct interface *ifp, struct connected *ifc)
169{
170  return kernel_address_delete_ipv4 (ifp, ifc);
171}
172#else /* ! HAVE_NETLINK */
173#ifdef HAVE_IFALIASREQ
174/* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
175   has ifaliasreq structure.  */
176int
177if_set_prefix (struct interface *ifp, struct connected *ifc)
178{
179  int ret;
180  struct ifaliasreq addreq;
181  struct sockaddr_in addr;
182  struct sockaddr_in mask;
183  struct prefix_ipv4 *p;
184
185  p = (struct prefix_ipv4 *) ifc->address;
186
187  memset (&addreq, 0, sizeof addreq);
188  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
189
190  memset (&addr, 0, sizeof (struct sockaddr_in));
191  addr.sin_addr = p->prefix;
192  addr.sin_family = p->family;
193#ifdef HAVE_SIN_LEN
194  addr.sin_len = sizeof (struct sockaddr_in);
195#endif
196  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
197
198  memset (&mask, 0, sizeof (struct sockaddr_in));
199  masklen2ip (p->prefixlen, &mask.sin_addr);
200  mask.sin_family = p->family;
201#ifdef HAVE_SIN_LEN
202  mask.sin_len = sizeof (struct sockaddr_in);
203#endif
204  memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
205
206  ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq);
207  if (ret < 0)
208    return ret;
209  return 0;
210}
211
212/* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
213   has ifaliasreq structure.  */
214int
215if_unset_prefix (struct interface *ifp, struct connected *ifc)
216{
217  int ret;
218  struct ifaliasreq addreq;
219  struct sockaddr_in addr;
220  struct sockaddr_in mask;
221  struct prefix_ipv4 *p;
222
223  p = (struct prefix_ipv4 *)ifc->address;
224
225  memset (&addreq, 0, sizeof addreq);
226  strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
227
228  memset (&addr, 0, sizeof (struct sockaddr_in));
229  addr.sin_addr = p->prefix;
230  addr.sin_family = p->family;
231#ifdef HAVE_SIN_LEN
232  addr.sin_len = sizeof (struct sockaddr_in);
233#endif
234  memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
235
236  memset (&mask, 0, sizeof (struct sockaddr_in));
237  masklen2ip (p->prefixlen, &mask.sin_addr);
238  mask.sin_family = p->family;
239#ifdef HAVE_SIN_LEN
240  mask.sin_len = sizeof (struct sockaddr_in);
241#endif
242  memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
243
244  ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq);
245  if (ret < 0)
246    return ret;
247  return 0;
248}
249#else
250/* Set up interface's address, netmask (and broadcas? ).  Linux or
251   Solaris uses ifname:number semantics to set IP address aliases. */
252int
253if_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    {
281      apply_mask_ipv4 (&ifaddr);
282      addr.sin_addr = ifaddr.prefix;
283
284      broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
285      broad.sin_family = p->family;
286
287      memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in));
288      ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq);
289      if (ret < 0)
290	return ret;
291    }
292
293  mask.sin_family = p->family;
294#ifdef SUNOS_5
295  memcpy (&mask, &ifreq.ifr_addr, sizeof (mask));
296#else
297  memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in));
298#endif /* SUNOS5 */
299  ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq);
300  if (ret < 0)
301    return ret;
302
303  return 0;
304}
305
306/* Set up interface's address, netmask (and broadcas? ).  Linux or
307   Solaris uses ifname:number semantics to set IP address aliases. */
308int
309if_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_IFALIASREQ */
330#endif /* HAVE_NETLINK */
331
332/* get interface flags */
333void
334if_get_flags (struct interface *ifp)
335{
336  int ret;
337  struct ifreq ifreq;
338
339  ifreq_set_name (&ifreq, ifp);
340
341  ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq);
342  if (ret < 0)
343    {
344      perror ("ioctl");
345      return;
346    }
347
348  ifp->flags = ifreq.ifr_flags & 0x0000ffff;
349}
350
351/* Set interface flags */
352int
353if_set_flags (struct interface *ifp, unsigned long flags)
354{
355  int ret;
356  struct ifreq ifreq;
357
358  ifreq_set_name (&ifreq, ifp);
359
360  ifreq.ifr_flags = ifp->flags;
361  ifreq.ifr_flags |= flags;
362
363  ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
364
365  if (ret < 0)
366    {
367#ifdef FOX_RIP_DEBUG
368      zlog_info ("can't set interface flags");
369#endif /* FOX_RIP_DEBUG */
370      return ret;
371    }
372  return 0;
373}
374
375/* Unset interface's flag. */
376int
377if_unset_flags (struct interface *ifp, unsigned long flags)
378{
379  int ret;
380  struct ifreq ifreq;
381
382  ifreq_set_name (&ifreq, ifp);
383
384  ifreq.ifr_flags = ifp->flags;
385  ifreq.ifr_flags &= ~flags;
386
387  ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
388
389  if (ret < 0)
390    {
391#ifdef FOX_RIP_DEBUG
392      zlog_info ("can't unset interface flags");
393#endif /* FOX_RIP_DEBUG */
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));
486
487  addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
488  addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
489
490  ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq);
491  if (ret < 0)
492    return ret;
493  return 0;
494}
495
496int
497if_prefix_delete_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_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_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_pltime = ND6_INFINITE_LIFETIME;
527  addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
528
529  ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq);
530  if (ret < 0)
531    return ret;
532  return 0;
533}
534#else
535int
536if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
537{
538  return 0;
539}
540
541int
542if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
543{
544  return 0;
545}
546#endif /* HAVE_IN6_ALIASREQ */
547
548#endif /* LINUX_IPV6 */
549
550#endif /* HAVE_IPV6 */
551