Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / krt-iface.c @ ba321706

History | View | Annotate | Download (5.21 KB)

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

    
10
#include <sys/types.h>
11
#include <sys/socket.h>
12
#include <netinet/in.h>
13
#include <net/if.h>
14
#include <sys/ioctl.h>
15
#include <errno.h>
16

    
17
#undef LOCAL_DEBUG
18

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

    
27
#include "unix.h"
28

    
29
int if_scan_sock = -1;
30

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

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

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

    
58
      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);
62
          if (l < 0 || !(l & IADDR_HOST))
63
            {
64
              log(L_ERR "%s: Invalid interface address", i.name);
65
              a.ip = IPA_NONE;
66
            }
67
          else
68
            {
69
              a.scope = l & IADDR_SCOPE_MASK;
70
              if (a.scope == SCOPE_HOST)
71
                i.flags |= IF_LOOPBACK | IF_IGNORE;
72
            }
73
        }
74

    
75
      if (ioctl(if_scan_sock, SIOCGIFFLAGS, r) < 0)
76
        {
77
          err = "SIOCGIFFLAGS";
78
        faulty:
79
          log(L_ERR "%s(%s): %m", err, i.name);
80
        bad:
81
          i.flags = (i.flags & ~IF_LINK_UP) | IF_ADMIN_DOWN;
82
          continue;
83
        }
84
      fl = r->ifr_flags;
85
      if (fl & IFF_UP)
86
        i.flags |= IF_LINK_UP;
87

    
88
      if (ioctl(if_scan_sock, SIOCGIFNETMASK, r) < 0)
89
        { 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
          goto bad;
96
        }
97
      a.pxlen = l;
98

    
99
      if (fl & IFF_POINTOPOINT)
100
        {
101
          a.flags |= IA_UNNUMBERED;
102
          if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
103
            { err = "SIOCGIFDSTADDR"; goto faulty; }
104
          get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL, 1);
105
          a.prefix = a.opposite;
106
          a.pxlen = BITS_PER_IP_ADDRESS;
107
        }
108
      else
109
        a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen));
110
      if (fl & IFF_LOOPBACK)
111
        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_UNNUMBERED)
118
#endif
119
         )
120
        i.flags |= IF_MULTICAST;
121

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

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

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

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

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

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

    
195
  for(;;)
196
    {
197
      ic.ifc_buf = alloca(last_ifbuf_size);
198
      ic.ifc_len = last_ifbuf_size;
199
      res = ioctl(if_scan_sock, SIOCGIFCONF, &ic);
200
      if (res < 0 && errno != EFAULT)
201
        die("SIOCCGIFCONF: %m");
202
      if (res >= 0 && ic.ifc_len <= last_ifbuf_size)
203
        break;
204
      last_ifbuf_size *= 2;
205
      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
krt_if_construct(struct kif_config *c)
212
{
213
}
214

    
215
void
216
krt_if_start(struct kif_proto *p)
217
{
218
}
219

    
220
void
221
krt_if_shutdown(struct kif_proto *p)
222
{
223
}
224

    
225
void
226
krt_if_io_init(void)
227
{
228
  if_scan_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
229
  DBG("Using socket %d for interface and route scanning\n", if_scan_sock);
230
  if (if_scan_sock < 0)
231
    die("Cannot create scanning socket: %m");
232
}
233