Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (4.73 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
      debug("%s\n", r->ifr_ifrn.ifrn_name);
44
      strncpy(i.name, r->ifr_ifrn.ifrn_name, sizeof(i.name) - 1);
45
      i.name[sizeof(i.name) - 1] = 0;
46
      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &i.ip, NULL);
47
      l = ipa_classify(i.ip);
48
      if (l < 0 || !(l & IADDR_HOST))
49
        {
50
          log(L_ERR "%s: Invalid interface address", i.name);
51
          goto bad;
52
        }
53
      if ((l & IADDR_SCOPE_MASK) == SCOPE_HOST)
54
        i.flags |= IF_LOOPBACK | IF_IGNORE;
55

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

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

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

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

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

    
118
#ifdef SIOCGIFINDEX
119
      if (ioctl(if_scan_sock, SIOCGIFINDEX, r) < 0)
120
        DBG("SIOCGIFINDEX failed: %m\n");
121
      else
122
        i.index = r->ifr_ifindex;
123
#endif
124

    
125
      if_update(&i);
126
    }
127
  if_end_update();
128
}
129

    
130
static void
131
scan_if(timer *t)
132
{
133
  struct ifconf ic;
134
  static int last_ifbuf_size = 4*sizeof(struct ifreq);
135
  int res;
136
  struct krt_proto *p = t->data;
137

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

    
174
void
175
krt_if_start(struct krt_proto *p)
176
{
177
  struct krt_config *c = (struct krt_config *) p->p.cf;
178

    
179
  if_scan_timer = tm_new(p->p.pool);
180
  if_scan_timer->hook = scan_if;
181
  if_scan_timer->data = p;
182
  if_scan_timer->recurrent = c->ifopt.scan_time;
183
  scan_if(if_scan_timer);
184
  tm_start(if_scan_timer, c->ifopt.scan_time);
185
}
186

    
187
void
188
krt_if_preconfig(struct krt_config *c)
189
{
190
  c->ifopt.scan_time = 60;
191
}
192

    
193
void
194
krt_if_shutdown(struct krt_proto *p)
195
{
196
  tm_stop(if_scan_timer);
197
  /* FIXME: What should we do with interfaces? */
198
}
199

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