Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (4.69 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/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
#define 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

    
26
#include "unix.h"
27

    
28
int if_scan_sock = -1;
29

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

    
40
  if_start_update();
41
  for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++)
42
    {
43
      bzero(&i, sizeof(i));
44
      bzero(&a, sizeof(a));
45
      DBG("%s\n", r->ifr_name);
46
      if (strchr(r->ifr_name, ':'))
47
        {
48
          /* FIXME: Honour aliases as secondary addresses? */
49
          DBG("Alias, ignored.\n");
50
          continue;
51
        }
52
      strncpy(i.name, r->ifr_name, sizeof(i.name) - 1);
53
      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL);
54
      if (ipa_nonzero(a.ip))
55
        {
56
          l = ipa_classify(a.ip);
57
          if (l < 0 || !(l & IADDR_HOST))
58
            {
59
              log(L_ERR "%s: Invalid interface address", i.name);
60
              a.ip = IPA_NONE;
61
            }
62
          else
63
            {
64
              a.scope = l & IADDR_SCOPE_MASK;
65
              if (a.scope == SCOPE_HOST)
66
                i.flags |= IF_LOOPBACK | IF_IGNORE;
67
            }
68
        }
69

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

    
83
      if (ioctl(if_scan_sock, SIOCGIFNETMASK, r) < 0)
84
        { err = "SIOCGIFNETMASK"; goto faulty; }
85
      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &netmask, NULL);
86
      l = ipa_mklen(netmask);
87
      if (l < 0 || l == 31)
88
        {
89
          log(L_ERR "%s: Invalid netmask", i.name);
90
          goto bad;
91
        }
92
      a.pxlen = l;
93

    
94
      if (fl & IFF_POINTOPOINT)
95
        {
96
          i.flags |= IF_UNNUMBERED;
97
          a.pxlen = BITS_PER_IP_ADDRESS;
98
          if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
99
            { err = "SIOCGIFDSTADDR"; goto faulty; }
100
          get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL);
101
        }
102
      if (fl & IFF_LOOPBACK)
103
        i.flags |= IF_LOOPBACK | IF_IGNORE;
104
#ifndef CONFIG_ALL_MULTICAST
105
      if (fl & IFF_MULTICAST)
106
#endif
107
        i.flags |= IF_MULTICAST;
108

    
109
      a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen));
110
      if (a.pxlen < 32)
111
        {
112
          a.brd = ipa_or(a.prefix, ipa_not(ipa_mkmask(a.pxlen)));
113
          if (ipa_equal(a.ip, a.prefix) || ipa_equal(a.ip, a.brd))
114
            {
115
              log(L_ERR "%s: Using network or broadcast address for interface", i.name);
116
              goto bad;
117
            }
118
          if (fl & IFF_BROADCAST)
119
            i.flags |= IF_BROADCAST;
120
          if (a.pxlen < 30)
121
            i.flags |= IF_MULTIACCESS;
122
          else
123
            a.opposite = ipa_opposite(a.ip);
124
        }
125
      else
126
        a.brd = a.opposite;
127

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

    
132
#ifdef SIOCGIFINDEX
133
      if (ioctl(if_scan_sock, SIOCGIFINDEX, r) < 0)
134
        DBG("SIOCGIFINDEX failed: %m\n");
135
      else
136
        i.index = r->ifr_ifindex;
137
#else
138
      /* FIXME: What else? Guess ifindex (we need it at least for OSPF on unnumbered links)? */
139
#endif
140

    
141
      pi = if_update(&i);
142
      a.iface = pi;
143
      ifa_update(&a);
144
    }
145
  if_end_update();
146
}
147

    
148
void
149
krt_if_scan(struct kif_proto *p)
150
{
151
  struct ifconf ic;
152
  static int last_ifbuf_size = 4*sizeof(struct ifreq);
153
  int res;
154

    
155
  for(;;)
156
    {
157
      if (last_ifbuf_size)
158
        {
159
          struct ifreq *r = alloca(last_ifbuf_size);
160
          ic.ifc_ifcu.ifcu_req = r;
161
          ic.ifc_len = last_ifbuf_size;
162
          res = ioctl(if_scan_sock, SIOCGIFCONF, &ic);
163
          if (res < 0 && errno != EFAULT)
164
            die("SIOCCGIFCONF: %m");
165
          if (res >= 0 && ic.ifc_len < last_ifbuf_size)
166
            {
167
              scan_ifs(r, ic.ifc_len);
168
              break;
169
            }
170
        }
171
#ifdef CLEAN_WAY_WORKING_ONLY_ON_LINUX_2_1        /* FIXME */
172
      ic.ifc_req = NULL;
173
      ic.ifc_len = 999999999;
174
      if (ioctl(if_scan_sock, SIOCGIFCONF, &ic) < 0)
175
        die("SIOCIFCONF: %m");
176
      ic.ifc_len += sizeof(struct ifreq);
177
      if (last_ifbuf_size < ic.ifc_len)
178
        {
179
          last_ifbuf_size = ic.ifc_len;
180
          DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size);
181
        }
182
#else
183
      last_ifbuf_size *= 2;
184
      DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size);
185
#endif
186
    }
187
}
188

    
189
void
190
krt_if_preconfig(struct kif_config *c)
191
{
192
}
193

    
194
void
195
krt_if_start(struct kif_proto *p)
196
{
197
}
198

    
199
void
200
krt_if_shutdown(struct kif_proto *p)
201
{
202
}
203

    
204
void
205
krt_if_io_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
}