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