syslog for interface transitions; broadcast all unreachable before exit
[unix-history] / usr / src / sbin / routed / startup.c
CommitLineData
85d8a62e 1#ifndef lint
69b7ef61 2static char sccsid[] = "@(#)startup.c 4.7 (Berkeley) %G%";
85d8a62e
SL
3#endif
4
5/*
6 * Routing Table Management Daemon
7 */
7fe7fe74 8#include "defs.h"
ad34083f 9#include <sys/ioctl.h>
85d8a62e
SL
10#include <net/if.h>
11#include <nlist.h>
69b7ef61 12#include <syslog.h>
85d8a62e
SL
13
14struct interface *ifnet;
15int kmem = -1;
16int lookforinterfaces = 1;
17int performnlist = 1;
18int externalinterfaces = 0; /* # of remote and local interfaces */
ad34083f 19int gateway = 0; /* 1 if we are a gateway to parts beyond */
85d8a62e
SL
20
21struct nlist nl[] = {
22#define N_IFNET 0
23 { "_ifnet" },
7fe7fe74 24 { "" },
85d8a62e
SL
25};
26
27/*
28 * Probe the kernel through /dev/kmem to find the network
29 * interfaces which have configured themselves. If the
30 * interface is present but not yet up (for example an
31 * ARPANET IMP), set the lookforinterfaces flag so we'll
32 * come back later and look again.
33 */
34ifinit()
35{
36 struct interface *ifp;
37 struct ifnet ifs, *next;
38 char name[32], *cp, *index();
39
40 if (performnlist) {
41 nlist("/vmunix", nl);
42 if (nl[N_IFNET].n_value == 0) {
43 printf("ifnet: not in namelist\n");
44 goto bad;
45 }
46 performnlist = 0;
f804e046 47 if (gateway > 0)
ad34083f 48 rtdefault();
85d8a62e
SL
49 }
50 if (kmem < 0) {
51 kmem = open("/dev/kmem", 0);
52 if (kmem < 0) {
53 perror("/dev/kmem");
54 goto bad;
55 }
56 }
57 if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
58 read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) {
59 printf("ifnet: error reading kmem\n");
60 goto bad;
61 }
62 lookforinterfaces = 0;
63 while (next) {
64 if (lseek(kmem, (long)next, 0) == -1 ||
65 read(kmem, (char *)&ifs, sizeof (ifs)) != sizeof (ifs)) {
66 perror("read");
67 goto bad;
68 }
69 next = ifs.if_next;
70 if ((ifs.if_flags & IFF_UP) == 0) {
71 lookforinterfaces = 1;
72 continue;
73 }
74 /* already known to us? */
75 if (if_ifwithaddr(&ifs.if_addr))
76 continue;
77 /* argh, this'll have to change sometime */
78 if (ifs.if_addr.sa_family != AF_INET)
79 continue;
80 /* no one cares about software loopback interfaces */
81 if (ifs.if_net == LOOPBACKNET)
82 continue;
83 ifp = (struct interface *)malloc(sizeof (struct interface));
84 if (ifp == 0) {
85 printf("routed: out of memory\n");
86 break;
87 }
88 /*
89 * Count the # of directly connected networks
90 * and point to point links which aren't looped
91 * back to ourself. This is used below to
92 * decide if we should be a routing ``supplier''.
93 */
94 if ((ifs.if_flags & IFF_POINTOPOINT) == 0 ||
95 if_ifwithaddr(&ifs.if_dstaddr) == 0)
96 externalinterfaces++;
ad34083f
MK
97 if ((ifs.if_flags & IFF_LOCAL) == 0 && gateway == 0) {
98 /*
99 * If we have an interface to a non-local network,
100 * we are a candidate for use as a gateway.
101 */
102 gateway = 1;
103 rtdefault();
104 }
85d8a62e
SL
105 lseek(kmem, ifs.if_name, 0);
106 read(kmem, name, sizeof (name));
107 name[sizeof (name) - 1] = '\0';
108 cp = index(name, '\0');
109 *cp++ = ifs.if_unit + '0';
110 *cp = '\0';
111 ifp->int_name = malloc(strlen(name) + 1);
112 if (ifp->int_name == 0) {
113 fprintf(stderr, "routed: ifinit: out of memory\n");
114 goto bad; /* ??? */
115 }
116 strcpy(ifp->int_name, name);
117 ifp->int_addr = ifs.if_addr;
118 ifp->int_flags = ifs.if_flags | IFF_INTERFACE;
119 /* this works because broadaddr overlaps dstaddr */
120 ifp->int_broadaddr = ifs.if_broadaddr;
121 ifp->int_net = ifs.if_net;
122 ifp->int_metric = 0;
123 ifp->int_next = ifnet;
124 ifnet = ifp;
125 traceinit(ifp);
126 addrouteforif(ifp);
127 }
128 if (externalinterfaces > 1 && supplier < 0)
129 supplier = 1;
130 return;
131bad:
132 sleep(60);
7fe7fe74 133 close(kmem), close(s);
85d8a62e
SL
134 execv("/etc/routed", argv0);
135 _exit(0177);
136}
137
138addrouteforif(ifp)
139 struct interface *ifp;
140{
141 struct sockaddr_in net;
142 struct sockaddr *dst;
143 int state, metric;
144 struct rt_entry *rt;
145
146 if (ifp->int_flags & IFF_POINTOPOINT)
147 dst = &ifp->int_dstaddr;
148 else {
149 bzero((char *)&net, sizeof (net));
150 net.sin_family = AF_INET;
151 net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
152 dst = (struct sockaddr *)&net;
153 }
69b7ef61
MK
154 if (ifp->int_transitions++ > 0)
155 syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
85d8a62e
SL
156 rt = rtlookup(dst);
157 rtadd(dst, &ifp->int_addr, ifp->int_metric,
158 ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
159 if (rt)
160 rtdelete(rt);
161}
162
163/*
164 * As a concession to the ARPANET we read a list of gateways
165 * from /etc/gateways and add them to our tables. This file
166 * exists at each ARPANET gateway and indicates a set of ``remote''
167 * gateways (i.e. a gateway which we can't immediately determine
168 * if it's present or not as we can do for those directly connected
169 * at the hardware level). If a gateway is marked ``passive''
170 * in the file, then we assume it doesn't have a routing process
171 * of our design and simply assume it's always present. Those
172 * not marked passive are treated as if they were directly
173 * connected -- they're added into the interface list so we'll
174 * send them routing updates.
175 */
176gwkludge()
177{
178 struct sockaddr_in dst, gate;
179 FILE *fp;
180 char *type, *dname, *gname, *qual, buf[BUFSIZ];
181 struct interface *ifp;
182 int metric;
ad34083f 183 struct rt_entry route;
85d8a62e
SL
184
185 fp = fopen("/etc/gateways", "r");
186 if (fp == NULL)
187 return;
188 qual = buf;
189 dname = buf + 64;
190 gname = buf + ((BUFSIZ - 64) / 3);
191 type = buf + (((BUFSIZ - 64) * 2) / 3);
192 bzero((char *)&dst, sizeof (dst));
193 bzero((char *)&gate, sizeof (gate));
ad34083f 194 bzero((char *)&route, sizeof(route));
85d8a62e
SL
195 /* format: {net | host} XX gateway XX metric DD [passive]\n */
196#define readentry(fp) \
197 fscanf((fp), "%s %s gateway %s metric %d %s\n", \
198 type, dname, gname, &metric, qual)
199 for (;;) {
85d8a62e
SL
200 if (readentry(fp) == EOF)
201 break;
7fe7fe74 202 if (!getnetorhostname(type, dname, &dst))
85d8a62e 203 continue;
7fe7fe74 204 if (!gethostnameornumber(gname, &gate))
85d8a62e 205 continue;
ad34083f
MK
206 if (strcmp(qual, "passive") == 0) {
207 /*
208 * Passive entries aren't placed in our tables,
209 * only the kernel's, so we don't copy all of the
210 * external routing information within a net.
211 * Internal machines should use the default
212 * route to a suitable gateway (like us).
213 */
214 route.rt_dst = *(struct sockaddr *) &dst;
215 route.rt_router = *(struct sockaddr *) &gate;
216 route.rt_flags = RTF_UP;
217 if (strcmp(type, "host") == 0)
218 route.rt_flags |= RTF_HOST;
219 if (metric)
220 route.rt_flags |= RTF_GATEWAY;
221 (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt);
222 continue;
223 }
224 /* assume no duplicate entries */
225 externalinterfaces++;
85d8a62e
SL
226 ifp = (struct interface *)malloc(sizeof (*ifp));
227 bzero((char *)ifp, sizeof (*ifp));
228 ifp->int_flags = IFF_REMOTE;
229 /* can't identify broadcast capability */
230 ifp->int_net = inet_netof(dst.sin_addr);
231 if (strcmp(type, "host") == 0) {
232 ifp->int_flags |= IFF_POINTOPOINT;
233 ifp->int_dstaddr = *((struct sockaddr *)&dst);
234 }
85d8a62e
SL
235 ifp->int_addr = *((struct sockaddr *)&gate);
236 ifp->int_metric = metric;
237 ifp->int_next = ifnet;
238 ifnet = ifp;
239 addrouteforif(ifp);
240 }
241 fclose(fp);
242}
7fe7fe74
SL
243
244getnetorhostname(type, name, sin)
245 char *type, *name;
246 struct sockaddr_in *sin;
247{
248
249 if (strcmp(type, "net") == 0) {
250 struct netent *np = getnetbyname(name);
251 int n;
252
7fe7fe74
SL
253 if (np == 0)
254 n = inet_network(name);
20932249
SL
255 else {
256 if (np->n_addrtype != AF_INET)
257 return (0);
7fe7fe74 258 n = np->n_net;
20932249 259 }
7fe7fe74
SL
260 sin->sin_family = AF_INET;
261 sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
262 return (1);
263 }
264 if (strcmp(type, "host") == 0) {
265 struct hostent *hp = gethostbyname(name);
266
7fe7fe74
SL
267 if (hp == 0)
268 sin->sin_addr.s_addr = inet_addr(name);
20932249
SL
269 else {
270 if (hp->h_addrtype != AF_INET)
271 return (0);
7fe7fe74 272 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
20932249 273 }
7fe7fe74
SL
274 sin->sin_family = AF_INET;
275 return (1);
276 }
277 return (0);
278}
279
280gethostnameornumber(name, sin)
281 char *name;
282 struct sockaddr_in *sin;
283{
284 struct hostent *hp;
285
286 hp = gethostbyname(name);
287 if (hp) {
288 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
289 sin->sin_family = hp->h_addrtype;
290 return (1);
291 }
292 sin->sin_addr.s_addr = inet_addr(name);
293 sin->sin_family = AF_INET;
294 return (sin->sin_addr.s_addr != -1);
295}