krt-iface.c 5.14 KB
Newer Older
1 2 3
/*
 *	BIRD -- Unix Interface Scanning and Syncing
 *
4
 *	(c) 1998--2000 Martin Mares <mj@ucw.cz>
5
 *      (c) 2004       Ondrej Filip <feela@network.cz>
6 7 8 9
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

Martin Mareš's avatar
Martin Mareš committed
10
#include <sys/types.h>
11 12 13 14 15 16
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <errno.h>

17
#undef LOCAL_DEBUG
18 19 20

#include "nest/bird.h"
#include "nest/iface.h"
21 22
#include "nest/route.h"
#include "nest/protocol.h"
23
#include "lib/timer.h"
24
#include "lib/krt.h"
25
#include "lib/string.h"
26 27 28

#include "unix.h"

29
int if_scan_sock = -1;
30 31 32 33

static void
scan_ifs(struct ifreq *r, int cnt)
{
34 35
  struct iface i, *pi;
  struct ifa a;
36
  char *err, *colon;
37 38
  unsigned fl;
  ip_addr netmask;
39
  int l, scope;
40
  sockaddr *sa;
41

42
  if_start_update();
43 44
  for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++)
    {
45
      int sec = 0;
46
      bzero(&i, sizeof(i));
47
      bzero(&a, sizeof(a));
48
      if (colon = strchr(r->ifr_name, ':'))
49
	{
50 51 52
	  /* It's an alias -- let's interpret it as a secondary interface address */
	  sec = 1;
	  *colon = 0;
53
	}
Martin Mareš's avatar
Martin Mareš committed
54
      strncpy(i.name, r->ifr_name, sizeof(i.name) - 1);
55 56 57 58

      if(ioctl(if_scan_sock, SIOCGIFADDR,r)<0) continue;

      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL, 1);
59
      if (ipa_nonzero(a.ip))
60
	{
61
	  l = ipa_classify(a.ip);
Martin Mareš's avatar
Martin Mareš committed
62 63 64
	  if (l < 0 || !(l & IADDR_HOST))
	    {
	      log(L_ERR "%s: Invalid interface address", i.name);
65 66 67 68 69 70 71
	      a.ip = IPA_NONE;
	    }
	  else
	    {
	      a.scope = l & IADDR_SCOPE_MASK;
	      if (a.scope == SCOPE_HOST)
		i.flags |= IF_LOOPBACK | IF_IGNORE;
Martin Mareš's avatar
Martin Mareš committed
72
	    }
73 74 75 76 77 78 79 80
	}

      if (ioctl(if_scan_sock, SIOCGIFFLAGS, r) < 0)
	{
	  err = "SIOCGIFFLAGS";
	faulty:
	  log(L_ERR "%s(%s): %m", err, i.name);
	bad:
81
	  i.flags = (i.flags & ~IF_ADMIN_UP) | IF_SHUTDOWN;
82 83 84 85
	  continue;
	}
      fl = r->ifr_flags;
      if (fl & IFF_UP)
86
	i.flags |= IF_ADMIN_UP;
87 88 89

      if (ioctl(if_scan_sock, SIOCGIFNETMASK, r) < 0)
	{ err = "SIOCGIFNETMASK"; goto faulty; }
90
      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &netmask, NULL, 0);
91
      l = ipa_mklen(netmask);
92
      if (l < 0)
93
	{
94
	  log(L_ERR "%s: Invalid netmask (%x)", i.name, netmask);
95 96
	  goto bad;
	}
97
      a.pxlen = l;
98 99 100

      if (fl & IFF_POINTOPOINT)
	{
101
	  a.flags |= IA_PEER;
102 103
	  if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
	    { err = "SIOCGIFDSTADDR"; goto faulty; }
104
	  get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL, 1);
105 106
	  a.prefix = a.opposite;
	  a.pxlen = BITS_PER_IP_ADDRESS;
107
	}
108 109
      else
	a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen));
110 111
      if (fl & IFF_LOOPBACK)
	i.flags |= IF_LOOPBACK | IF_IGNORE;
112
      if (1
113
#ifndef CONFIG_ALL_MULTICAST
114
	  && (fl & IFF_MULTICAST)
115
#endif
116
#ifndef CONFIG_UNNUM_MULTICAST
117
	  && !(a.flags & IA_PEER)
118 119
#endif
	 )
120 121
	i.flags |= IF_MULTICAST;

122 123 124 125 126 127 128 129
      scope = ipa_classify(a.ip);
      if (scope < 0)
	{
	  log(L_ERR "%s: Invalid address", i.name);
	  goto bad;
	}
      a.scope = scope & IADDR_SCOPE_MASK;

130
      if (a.pxlen < 32)
131
	{
132 133
	  a.brd = ipa_or(a.prefix, ipa_not(ipa_mkmask(a.pxlen)));
	  if (ipa_equal(a.ip, a.prefix) || ipa_equal(a.ip, a.brd))
134 135 136 137 138 139
	    {
	      log(L_ERR "%s: Using network or broadcast address for interface", i.name);
	      goto bad;
	    }
	  if (fl & IFF_BROADCAST)
	    i.flags |= IF_BROADCAST;
140
	  if (a.pxlen < 30)
141
	    i.flags |= IF_MULTIACCESS;
142 143 144 145
	  if (a.pxlen == 30)
	    ifa.opposite = ipa_opposite_m2(ifa.ip);
	  if (a.pxlen == 31)
	    ifa.opposite = ipa_opposite_m1(ifa.ip);
146 147
	}
      else
148
	a.brd = a.opposite;
149
      a.scope = SCOPE_UNIVERSE;
150 151 152 153 154 155

      if (ioctl(if_scan_sock, SIOCGIFMTU, r) < 0)
	{ err = "SIOCGIFMTU"; goto faulty; }
      i.mtu = r->ifr_mtu;

#ifdef SIOCGIFINDEX
156
      if (ioctl(if_scan_sock, SIOCGIFINDEX, r) >= 0)
157
	i.index = r->ifr_ifindex;
158
      else if (errno != EINVAL)
159 160 161
	DBG("SIOCGIFINDEX failed: %m\n");
      else	/* defined, but not supported by the kernel */
#endif
162 163 164 165 166 167 168 169 170 171 172
      /*
       *  The kernel doesn't give us real ifindices, but we still need them
       *  at least for OSPF unnumbered links. So let's make them up ourselves.
       */
      if (pi = if_find_by_name(i.name))
	i.index = pi->index;
      else
	{
	  static int if_index_counter = 1;
	  i.index = if_index_counter++;
	}
173

174 175 176 177 178 179 180 181
      pi = NULL;
      if (sec)
	{
	  a.flags |= IA_SECONDARY;
	  pi = if_find_by_index(i.index);
	}
      if (!pi)
	pi = if_update(&i);
182 183
      a.iface = pi;
      ifa_update(&a);
184
    }
185
  if_end_update();
186 187
}

188
void
189
kif_do_scan(struct kif_proto *p)
190 191
{
  struct ifconf ic;
192
  static int last_ifbuf_size = 4*sizeof(struct ifreq);
193 194 195 196
  int res;

  for(;;)
    {
197 198 199 200 201 202 203
      ic.ifc_buf = alloca(last_ifbuf_size);
      ic.ifc_len = last_ifbuf_size;
      res = ioctl(if_scan_sock, SIOCGIFCONF, &ic);
      if (res < 0 && errno != EFAULT)
        die("SIOCCGIFCONF: %m");
      if (res >= 0 && ic.ifc_len <= last_ifbuf_size)
        break;
204 205
      last_ifbuf_size *= 2;
      DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size);
206
    }
207
  scan_ifs(ic.ifc_req, ic.ifc_len);
208 209 210
}

void
211
kif_start(struct kif_proto *p)
212 213 214 215
{
}

void
216
kif_shutdown(struct kif_proto *p)
217 218 219 220
{
}

void
221
kif_io_init(void)
222
{
223 224 225 226
  if_scan_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
  DBG("Using socket %d for interface and route scanning\n", if_scan_sock);
  if (if_scan_sock < 0)
    die("Cannot create scanning socket: %m");
227
}
228