]>
Commit | Line | Data |
---|---|---|
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 | ||
27 | int if_scan_sock; | |
8a48ecb8 MM |
28 | |
29 | static timer *if_scan_timer; | |
30 | ||
31 | static void | |
32 | scan_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 | ||
130 | static void | |
131 | scan_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 | ||
174 | void | |
175 | krt_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 | ||
185 | void | |
186 | krt_if_preconfig(struct krt_proto *p) | |
187 | { | |
188 | p->ifopt.scan_time = 60; | |
189 | } | |
190 | ||
191 | void | |
192 | krt_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 | ||
199 | void | |
200 | scan_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 | } |