]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/unix/sync-if.c
Hopefully finished kernel syncer (krt) rewrite:
[thirdparty/bird.git] / sysdep / unix / sync-if.c
CommitLineData
8a48ecb8
MM
1/*
2 * BIRD -- Unix Interface Scanning and Syncing
3 *
4 * (c) 1998 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"
8e66a0eb
MM
20#include "nest/route.h"
21#include "nest/protocol.h"
8a48ecb8 22#include "lib/timer.h"
8e66a0eb 23#include "lib/krt.h"
8a48ecb8
MM
24
25#include "unix.h"
26
27int if_scan_sock;
8a48ecb8
MM
28
29static timer *if_scan_timer;
30
31static void
32scan_ifs(struct ifreq *r, int cnt)
33{
34 struct iface i;
8a48ecb8
MM
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));
8a48ecb8
MM
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;
869c6959
MM
46 get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &i.ip, NULL);
47 l = ipa_classify(i.ip);
8a48ecb8
MM
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 }
869c6959 78 i.pxlen = l;
8a48ecb8
MM
79
80 if (fl & IFF_POINTOPOINT)
81 {
82 i.flags |= IF_UNNUMBERED;
869c6959 83 i.pxlen = BITS_PER_IP_ADDRESS;
8a48ecb8
MM
84 if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
85 { err = "SIOCGIFDSTADDR"; goto faulty; }
869c6959 86 get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &i.opposite, NULL);
8a48ecb8
MM
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
869c6959
MM
95 i.prefix = ipa_and(i.ip, ipa_mkmask(i.pxlen));
96 if (i.pxlen < 32)
8a48ecb8 97 {
869c6959
MM
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))
8a48ecb8
MM
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;
869c6959 106 if (i.pxlen < 30)
8a48ecb8
MM
107 i.flags |= IF_MULTIACCESS;
108 else
869c6959 109 i.opposite = ipa_opposite(i.ip);
8a48ecb8
MM
110 }
111 else
869c6959 112 i.brd = i.opposite;
8a48ecb8
MM
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)
c93214d4
MM
120 DBG("SIOCGIFINDEX failed: %m\n");
121 else
122 i.index = r->ifr_ifindex;
8a48ecb8
MM
123#endif
124
125 if_update(&i);
126 }
869c6959 127 if_end_update();
8a48ecb8
MM
128}
129
130static void
131scan_if(timer *t)
132{
133 struct ifconf ic;
c93214d4 134 static int last_ifbuf_size = 4*sizeof(struct ifreq);
8a48ecb8 135 int res;
8e66a0eb 136 struct krt_proto *p = t->data;
8a48ecb8 137
8e66a0eb 138 DBG("It's interface scan time...\n");
8a48ecb8
MM
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);
c93214d4 147 if (res < 0 && errno != EFAULT)
8a48ecb8
MM
148 die("SIOCCGIFCONF: %m");
149 if (res < last_ifbuf_size)
150 {
151 scan_ifs(r, ic.ifc_len);
152 break;
153 }
154 }
c93214d4
MM
155#ifdef CLEAN_WAY_WORKING_ONLY_ON_LINUX_2_1 /* FIXME */
156 ic.ifc_req = NULL;
fdf33cde 157 ic.ifc_len = 999999999;
8a48ecb8
MM
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 }
c93214d4
MM
166#else
167 last_ifbuf_size *= 2;
168 DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size);
169#endif
8a48ecb8 170 }
8e66a0eb
MM
171 krt_scan_ifaces_done(p);
172}
173
174void
175krt_if_start(struct krt_proto *p)
176{
177 if_scan_timer = tm_new(&root_pool);
178 if_scan_timer->hook = scan_if;
179 if_scan_timer->data = p;
180 if_scan_timer->recurrent = p->ifopt.scan_time;
181 scan_if(if_scan_timer);
182 tm_start(if_scan_timer, p->ifopt.scan_time);
183}
184
185void
186krt_if_preconfig(struct krt_proto *p)
187{
188 p->ifopt.scan_time = 60;
189}
190
191void
192krt_if_shutdown(struct krt_proto *p)
193{
194 tm_stop(if_scan_timer);
195 rfree(if_scan_timer);
196 /* FIXME: What should we do with interfaces? */
8a48ecb8
MM
197}
198
199void
200scan_if_init(void)
201{
567e6c62 202 if_scan_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
8a48ecb8
MM
203 DBG("Using socket %d for interface and route scanning\n", if_scan_sock);
204 if (if_scan_sock < 0)
205 die("Cannot create scanning socket: %m");
8a48ecb8 206}