tools/llvm: Do not build with symbols
[minix3.git] / minix / commands / rarpd / rarpd.c
blobcf4962651b9897e1cfdcf21c5575148e4b8d6bec
1 /*
2 rarpd.c
4 Created: Nov 12, 1992 by Philip Homburg
6 Changed: May 13, 1995 by Kees J. Bot
7 Rewrite to handle multiple ethernets.
9 Changed: Jul 18, 1995 by Kees J. Bot
10 Do RARP requests (formerly inet's job)
12 Changed: Dec 14, 1996 by Kees J. Bot
13 Query the netmask
15 Changed: Dec 11, 2000 by Kees J. Bot
16 Dressed down to be only a RARP server, giving the floor to DHCP
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/asynchio.h>
29 #include <net/hton.h>
30 #include <net/gen/socket.h>
31 #include <netdb.h>
32 #include <net/gen/in.h>
33 #include <net/gen/inet.h>
34 #include <net/gen/ether.h>
35 #include <net/gen/eth_io.h>
36 #include <net/gen/if_ether.h>
37 #include <net/gen/ip_io.h>
38 #include <arpa/nameser.h>
40 #define MAX_RARP_RETRIES 5
41 #define RARP_TIMEOUT 5
43 #undef HTONS
44 #define HTONS htons
46 typedef struct rarp46
48 ether_addr_t a46_dstaddr;
49 ether_addr_t a46_srcaddr;
50 ether_type_t a46_ethtype;
51 u16_t a46_hdr, a46_pro;
52 u8_t a46_hln, a46_pln;
53 u16_t a46_op;
54 ether_addr_t a46_sha;
55 u8_t a46_spa[4];
56 ether_addr_t a46_tha;
57 u8_t a46_tpa[4];
58 char a46_padding[ETH_MIN_PACK_SIZE - (4*6 + 2*4 + 4*2 + 2*1)];
59 } rarp46_t;
61 #define ETH_RARP_PROTO 0x8035
63 #define RARP_ETHERNET 1
65 #define RARP_REQUEST 3
66 #define RARP_REPLY 4
68 static char *program;
69 static unsigned debug;
71 #define between(a, c, z) ((unsigned) (c) - (a) <= (unsigned) (z) - (a))
73 static void report(const char *label)
75 fprintf(stderr, "%s: %s: %s\n", program, label, strerror(errno));
78 static void fatal(const char *label)
80 report(label);
81 exit(1);
84 static void *allocate(size_t size)
86 void *mem;
88 if ((mem= malloc(size)) == NULL) fatal("Can't allocate memory");
89 return mem;
92 static char *ethdev(int n)
94 static char an_ethdev[]= "/dev/ethNNN";
96 sprintf(an_ethdev + sizeof(an_ethdev)-4, "%d", n);
97 return an_ethdev;
100 static char *ipdev(int n)
102 static char an_ipdev[]= "/dev/ipNNN";
104 sprintf(an_ipdev + sizeof(an_ipdev)-4, "%d", n);
105 return an_ipdev;
108 typedef struct ethernet {
109 int n; /* Network number. */
110 int eth_fd; /* Open low level ethernet device. */
111 ether_addr_t eth_addr; /* Ethernet address of this net. */
112 char packet[ETH_MAX_PACK_SIZE]; /* Incoming packet. */
113 ipaddr_t ip_addr; /* IP address of this net. */
114 ipaddr_t ip_mask; /* Associated netmask. */
115 } ethernet_t;
117 static ethernet_t *ethernets;
119 static void onsig(int sig)
121 switch (sig) {
122 case SIGUSR1: debug++; break;
123 case SIGUSR2: debug= 0; break;
127 static void rarp_reply(ethernet_t *ep, char *hostname, ipaddr_t ip_addr,
128 ether_addr_t eth_addr)
130 rarp46_t rarp46;
132 /* Construct a RARP reply packet and send it. */
133 rarp46.a46_dstaddr= eth_addr;
134 rarp46.a46_hdr= HTONS(RARP_ETHERNET);
135 rarp46.a46_pro= HTONS(ETH_IP_PROTO);
136 rarp46.a46_hln= 6;
137 rarp46.a46_pln= 4;
138 rarp46.a46_op= HTONS(RARP_REPLY);
139 rarp46.a46_sha= ep->eth_addr;
140 memcpy(rarp46.a46_spa, &ep->ip_addr, sizeof(ipaddr_t));
141 rarp46.a46_tha= eth_addr;
142 memcpy(rarp46.a46_tpa, &ip_addr, sizeof(ipaddr_t));
144 if (debug >= 1) {
145 printf("%s: Replying %s (%s) to %s\n",
146 ethdev(ep->n), inet_ntoa(ip_addr), hostname, ether_ntoa(&eth_addr));
148 (void) write(ep->eth_fd, &rarp46, sizeof(rarp46));
151 static int addhostname(char *addname, char *hostname, int n)
153 /* Create an additional hostname for a given hostname by adding "-n" to
154 * the first part. E.g. given "wombat.cs.vu.nl" and n=2 return
155 * "wombat-2.cs.vu.nl". This is useful for VU practical work where
156 * people get a few extra ethernet addresses on a machine and are asked
157 * to build a TCP/IP stack on it.
159 char *dot;
161 if (strlen(hostname) + 4 >= 1024) return 0;
162 if ((dot= strchr(hostname, '.')) == NULL) dot= strchr(hostname, 0);
163 sprintf(addname, "%.*s-%d%s", (dot - hostname), hostname, n, dot);
164 return 1;
167 static void usage(void)
169 fprintf(stderr, "Usage: %s [-d[level]] network-name ...\n", program);
170 exit(1);
173 static int ifname2n(const char *name)
175 /* Translate an interface name, ip0, ip1, etc, to a number. */
176 const char *np;
177 char *end;
178 unsigned long n;
180 np= name;
181 if (*np++ != 'i' || *np++ != 'p') usage();
182 n= strtoul(np, &end, 10);
183 if (end == np || *end != 0) usage();
184 if (n >= 1000) {
185 fprintf(stderr, "%s: Network number of \"%s\" is a bit large\n",
186 program, name);
187 exit(1);
189 return n;
192 int main(int argc, char **argv)
194 int i;
195 ethernet_t *ep;
196 nwio_ethopt_t ethopt;
197 nwio_ethstat_t ethstat;
198 char hostname[1024];
199 struct hostent *hostent;
200 struct sigaction sa;
201 nwio_ipconf_t ipconf;
202 asynchio_t asyn;
203 ssize_t n;
204 ipaddr_t ip_addr;
205 rarp46_t rarp46;
206 int fd;
207 int n_eths;
209 program= argv[0];
210 asyn_init(&asyn);
212 debug= 0;
213 i= 1;
214 while (i < argc && argv[i][0] == '-') {
215 char *opt= argv[i++]+1;
217 if (opt[0] == '-' && opt[1] == 0) break; /* -- */
219 while (*opt != 0) switch (*opt++) {
220 case 'd':
221 debug= 1;
222 if (between('0', *opt, '9')) debug= strtoul(opt, &opt, 10);
223 break;
224 default:
225 usage();
229 if ((n_eths= (argc - i)) == 0) usage();
231 #if __minix_vmd
232 /* Minix-vmd can handle all nets at once using async I/O. */
233 ethernets= allocate(n_eths * sizeof(ethernets[0]));
234 for (i= 0; i < n_eths; i++) {
235 ethernets[i].n= ifname2n(argv[argc - n_eths + i]);
237 #else
238 /* Minix forks n-1 times to handle each net in a process each. */
239 for (i= 0; i < n_eths; i++) {
240 if (i+1 < n_eths) {
241 switch (fork()) {
242 case -1: fatal("fork()");
243 case 0: break;
244 default: continue;
247 ethernets= allocate(1 * sizeof(ethernets[0]));
248 ethernets[0].n= ifname2n(argv[argc - n_eths + i]);
250 n_eths= 1;
251 #endif
253 sa.sa_handler= onsig;
254 sigemptyset(&sa.sa_mask);
255 sa.sa_flags= 0;
256 sigaction(SIGUSR1, &sa, NULL);
257 sigaction(SIGUSR2, &sa, NULL);
259 for (i= 0; i < n_eths; i++) {
260 ep= &ethernets[i];
261 if ((ep->eth_fd= open(ethdev(ep->n), O_RDWR)) < 0) fatal(ethdev(ep->n));
263 if (ioctl(ep->eth_fd, NWIOGETHSTAT, &ethstat) < 0) {
264 fprintf(stderr, "%s: %s: Unable to get eth statistics: %s\n",
265 program, ethdev(ep->n), strerror(errno));
266 exit(1);
268 ep->eth_addr= ethstat.nwes_addr;
269 if (debug >= 1) {
270 printf("%s: Ethernet address is %s\n",
271 ethdev(ep->n), ether_ntoa(&ep->eth_addr));
274 ethopt.nweo_flags= NWEO_COPY | NWEO_EN_LOC | NWEO_EN_BROAD |
275 NWEO_TYPESPEC;
276 ethopt.nweo_type= HTONS(ETH_RARP_PROTO);
278 if (ioctl(ep->eth_fd, NWIOSETHOPT, &ethopt) < 0) {
279 fprintf(stderr, "%s: %s: Unable to set eth options: %s\n",
280 program, ethdev(ep->n), strerror(errno));
281 exit(1);
284 /* What are my address and netmask? */
285 if ((fd= open(ipdev(ep->n), O_RDWR)) < 0) fatal(ipdev(ep->n));
286 if (ioctl(fd, NWIOGIPCONF, &ipconf) < 0) fatal(ipdev(ep->n));
288 ep->ip_addr= ipconf.nwic_ipaddr;
289 ep->ip_mask= ipconf.nwic_netmask;
290 close(fd);
291 if (debug >= 1) {
292 printf("%s: IP address is %s / ",
293 ipdev(ep->n), inet_ntoa(ep->ip_addr));
294 printf("%s\n", inet_ntoa(ep->ip_mask));
298 /* Wait for RARP requests, reply, repeat. */
299 for(;;) {
300 fflush(NULL);
302 /* Wait for a RARP request. */
303 for (i= 0; i < n_eths; i++) {
304 ep= &ethernets[i];
306 n= asyn_read(&asyn, ep->eth_fd, ep->packet, sizeof(ep->packet));
307 if (n != -1) break;
308 if (errno != EINPROGRESS) {
309 report(ethdev(ep->n));
310 sleep(10);
314 /* RARP request? */
315 if (i < n_eths
316 && n >= sizeof(rarp46)
317 && (memcpy(&rarp46, ep->packet, sizeof(rarp46)), 1)
318 && rarp46.a46_hdr == HTONS(RARP_ETHERNET)
319 && rarp46.a46_pro == HTONS(ETH_IP_PROTO)
320 && rarp46.a46_hln == 6
321 && rarp46.a46_pln == 4
322 && rarp46.a46_op == HTONS(RARP_REQUEST)
324 if ((ether_ntohost(hostname, &rarp46.a46_tha) == 0
325 || (rarp46.a46_tha.ea_addr[0] == 'v'
326 && (memcpy(&ip_addr, rarp46.a46_tha.ea_addr+2, 4), 1)
327 && (hostent= gethostbyaddr((char*) &ip_addr,
328 4, AF_INET)) != NULL
329 && addhostname(hostname, hostent->h_name,
330 rarp46.a46_tha.ea_addr[1])))
331 && (hostent= gethostbyname(hostname)) != NULL
332 && hostent->h_addrtype == AF_INET
334 /* Host is found in the ethers file and the DNS, or the
335 * ethernet address denotes a special additional address
336 * used for implementing a TCP/IP stack in user space.
338 for (i= 0; hostent->h_addr_list[i] != NULL; i++) {
339 memcpy(&ip_addr, hostent->h_addr_list[i], sizeof(ipaddr_t));
341 /* Check if the address is on this network. */
342 if (((ip_addr ^ ep->ip_addr) & ep->ip_mask) == 0) break;
345 if (hostent->h_addr_list[i] != NULL) {
346 rarp_reply(ep, hostname, ip_addr, rarp46.a46_tha);
347 } else {
348 if (debug >= 2) {
349 printf("%s: Host '%s' (%s) is on the wrong net\n",
350 ethdev(ep->n),
351 hostname, ether_ntoa(&rarp46.a46_tha));
354 } else {
355 if (debug >= 2) {
356 printf("%s: RARP request from unknown host '%s'\n",
357 ethdev(ep->n), ether_ntoa(&rarp46.a46_tha));
362 /* Wait for another request. */
363 if (asyn_wait(&asyn, 0, NULL) < 0) {
364 report("asyn_wait()");
365 sleep(10);