Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / sync-if.c @ bcbd8cc3

History | View | Annotate | Download (4.86 KB)

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

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

    
16
#define LOCAL_DEBUG
17

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

    
25
#include "unix.h"
26

    
27
int if_scan_sock;
28

    
29
static timer *if_scan_timer;
30

    
31
static void
32
scan_ifs(struct ifreq *r, int cnt)
33
{
34
  struct iface i;
35
  char *err;
36
  unsigned fl;
37
  ip_addr netmask;
38
  int l;
39

    
40
  for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++)
41
    {
42
      bzero(&i, sizeof(i));
43
      DBG("%s\n", r->ifr_ifrn.ifrn_name);
44
      strncpy(i.name, r->ifr_ifrn.ifrn_name, sizeof(i.name) - 1);
45
      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &i.ip, NULL);
46
      if (ipa_nonzero(i.ip))
47
        {
48
          l = ipa_classify(i.ip);
49
          if (l < 0 || !(l & IADDR_HOST))
50
            {
51
              log(L_ERR "%s: Invalid interface address", i.name);
52
              i.ip = IPA_NONE;
53
            }
54
          else if ((l & IADDR_SCOPE_MASK) == SCOPE_HOST)
55
            i.flags |= IF_LOOPBACK | IF_IGNORE;
56
        }
57

    
58
      if (ioctl(if_scan_sock, SIOCGIFFLAGS, r) < 0)
59
        {
60
          err = "SIOCGIFFLAGS";
61
        faulty:
62
          log(L_ERR "%s(%s): %m", err, i.name);
63
        bad:
64
          i.flags = (i.flags & ~IF_LINK_UP) | IF_ADMIN_DOWN;
65
          continue;
66
        }
67
      fl = r->ifr_flags;
68
      if (fl & IFF_UP)
69
        i.flags |= IF_LINK_UP;
70

    
71
      if (ioctl(if_scan_sock, SIOCGIFNETMASK, r) < 0)
72
        { err = "SIOCGIFNETMASK"; goto faulty; }
73
      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &netmask, NULL);
74
      l = ipa_mklen(netmask);
75
      if (l < 0 || l == 31)
76
        {
77
          log(L_ERR "%s: Invalid netmask", i.name);
78
          goto bad;
79
        }
80
      i.pxlen = l;
81

    
82
      if (fl & IFF_POINTOPOINT)
83
        {
84
          i.flags |= IF_UNNUMBERED;
85
          i.pxlen = BITS_PER_IP_ADDRESS;
86
          if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
87
            { err = "SIOCGIFDSTADDR"; goto faulty; }
88
          get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &i.opposite, NULL);
89
        }
90
      if (fl & IFF_LOOPBACK)
91
        i.flags |= IF_LOOPBACK | IF_IGNORE;
92
#ifndef CONFIG_ALL_MULTICAST
93
      if (fl & IFF_MULTICAST)
94
#endif
95
        i.flags |= IF_MULTICAST;
96

    
97
      i.prefix = ipa_and(i.ip, ipa_mkmask(i.pxlen));
98
      if (i.pxlen < 32)
99
        {
100
          i.brd = ipa_or(i.prefix, ipa_not(ipa_mkmask(i.pxlen)));
101
          if (ipa_equal(i.ip, i.prefix) || ipa_equal(i.ip, i.brd))
102
            {
103
              log(L_ERR "%s: Using network or broadcast address for interface", i.name);
104
              goto bad;
105
            }
106
          if (fl & IFF_BROADCAST)
107
            i.flags |= IF_BROADCAST;
108
          if (i.pxlen < 30)
109
            i.flags |= IF_MULTIACCESS;
110
          else
111
            i.opposite = ipa_opposite(i.ip);
112
        }
113
      else
114
        i.brd = i.opposite;
115

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

    
120
#ifdef SIOCGIFINDEX
121
      if (ioctl(if_scan_sock, SIOCGIFINDEX, r) < 0)
122
        DBG("SIOCGIFINDEX failed: %m\n");
123
      else
124
        i.index = r->ifr_ifindex;
125
#else
126
      /* FIXME: What else? Guess ifindex (we need it at least for OSPF on unnumbered links)? */
127
#endif
128

    
129
      if_update(&i);
130
    }
131
  if_end_update();
132
}
133

    
134
static void
135
scan_if(timer *t)
136
{
137
  struct ifconf ic;
138
  static int last_ifbuf_size = 4*sizeof(struct ifreq);
139
  int res;
140
  struct krt_proto *p = t->data;
141

    
142
  DBG("It's interface scan time...\n");
143
  for(;;)
144
    {
145
      if (last_ifbuf_size)
146
        {
147
          struct ifreq *r = alloca(last_ifbuf_size);
148
          ic.ifc_ifcu.ifcu_req = r;
149
          ic.ifc_len = last_ifbuf_size;
150
          res = ioctl(if_scan_sock, SIOCGIFCONF, &ic);
151
          if (res < 0 && errno != EFAULT)
152
            die("SIOCCGIFCONF: %m");
153
          if (res < last_ifbuf_size)
154
            {
155
              scan_ifs(r, ic.ifc_len);
156
              break;
157
            }
158
        }
159
#ifdef CLEAN_WAY_WORKING_ONLY_ON_LINUX_2_1        /* FIXME */
160
      ic.ifc_req = NULL;
161
      ic.ifc_len = 999999999;
162
      if (ioctl(if_scan_sock, SIOCGIFCONF, &ic) < 0)
163
        die("SIOCIFCONF: %m");
164
      ic.ifc_len += sizeof(struct ifreq);
165
      if (last_ifbuf_size < ic.ifc_len)
166
        {
167
          last_ifbuf_size = ic.ifc_len;
168
          DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size);
169
        }
170
#else
171
      last_ifbuf_size *= 2;
172
      DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size);
173
#endif
174
    }
175
  krt_scan_ifaces_done(p);
176
}
177

    
178
void
179
krt_if_start(struct krt_proto *p)
180
{
181
  struct krt_config *c = (struct krt_config *) p->p.cf;
182

    
183
  if_scan_timer = tm_new(p->p.pool);
184
  if_scan_timer->hook = scan_if;
185
  if_scan_timer->data = p;
186
  if_scan_timer->recurrent = c->ifopt.scan_time;
187
  scan_if(if_scan_timer);
188
  tm_start(if_scan_timer, c->ifopt.scan_time);
189
}
190

    
191
void
192
krt_if_preconfig(struct krt_config *c)
193
{
194
  c->ifopt.scan_time = 60;
195
}
196

    
197
void
198
krt_if_shutdown(struct krt_proto *p)
199
{
200
  tm_stop(if_scan_timer);
201
  /* FIXME: What should we do with interfaces? */
202
}
203

    
204
void
205
scan_if_init(void)
206
{
207
  if_scan_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
208
  DBG("Using socket %d for interface and route scanning\n", if_scan_sock);
209
  if (if_scan_sock < 0)
210
    die("Cannot create scanning socket: %m");
211
}