pci: don't do sanity check for missing pci bus, the check can misfire.
[minix.git] / commands / simple / rarpd.c
blobabb1872ea5dd86d037ecf8a42f63691d933e7bdc
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 <net/gen/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 <net/gen/nameser.h>
40 #define MAX_RARP_RETRIES 5
41 #define RARP_TIMEOUT 5
43 typedef struct rarp46
45 ether_addr_t a46_dstaddr;
46 ether_addr_t a46_srcaddr;
47 ether_type_t a46_ethtype;
48 u16_t a46_hdr, a46_pro;
49 u8_t a46_hln, a46_pln;
50 u16_t a46_op;
51 ether_addr_t a46_sha;
52 u8_t a46_spa[4];
53 ether_addr_t a46_tha;
54 u8_t a46_tpa[4];
55 char a46_padding[ETH_MIN_PACK_SIZE - (4*6 + 2*4 + 4*2 + 2*1)];
56 } rarp46_t;
58 #define ETH_RARP_PROTO 0x8035
60 #define RARP_ETHERNET 1
62 #define RARP_REQUEST 3
63 #define RARP_REPLY 4
65 static char *program;
66 static unsigned debug;
68 #define between(a, c, z) ((unsigned) (c) - (a) <= (unsigned) (z) - (a))
70 static void report(const char *label)
72 fprintf(stderr, "%s: %s: %s\n", program, label, strerror(errno));
75 static void fatal(const char *label)
77 report(label);
78 exit(1);
81 static void *allocate(size_t size)
83 void *mem;
85 if ((mem= malloc(size)) == NULL) fatal("Can't allocate memory");
86 return mem;
89 static char *ethdev(int n)
91 static char an_ethdev[]= "/dev/ethNNN";
93 sprintf(an_ethdev + sizeof(an_ethdev)-4, "%d", n);
94 return an_ethdev;
97 static char *ipdev(int n)
99 static char an_ipdev[]= "/dev/ipNNN";
101 sprintf(an_ipdev + sizeof(an_ipdev)-4, "%d", n);
102 return an_ipdev;
105 typedef struct ethernet {
106 int n; /* Network number. */
107 int eth_fd; /* Open low level ethernet device. */
108 ether_addr_t eth_addr; /* Ethernet address of this net. */
109 char packet[ETH_MAX_PACK_SIZE]; /* Incoming packet. */
110 ipaddr_t ip_addr; /* IP address of this net. */
111 ipaddr_t ip_mask; /* Associated netmask. */
112 } ethernet_t;
114 static ethernet_t *ethernets;
116 static void onsig(int sig)
118 switch (sig) {
119 case SIGUSR1: debug++; break;
120 case SIGUSR2: debug= 0; break;
124 static void rarp_reply(ethernet_t *ep, char *hostname, ipaddr_t ip_addr,
125 ether_addr_t eth_addr)
127 rarp46_t rarp46;
129 /* Construct a RARP reply packet and send it. */
130 rarp46.a46_dstaddr= eth_addr;
131 rarp46.a46_hdr= HTONS(RARP_ETHERNET);
132 rarp46.a46_pro= HTONS(ETH_IP_PROTO);
133 rarp46.a46_hln= 6;
134 rarp46.a46_pln= 4;
135 rarp46.a46_op= HTONS(RARP_REPLY);
136 rarp46.a46_sha= ep->eth_addr;
137 memcpy(rarp46.a46_spa, &ep->ip_addr, sizeof(ipaddr_t));
138 rarp46.a46_tha= eth_addr;
139 memcpy(rarp46.a46_tpa, &ip_addr, sizeof(ipaddr_t));
141 if (debug >= 1) {
142 printf("%s: Replying %s (%s) to %s\n",
143 ethdev(ep->n), inet_ntoa(ip_addr), hostname, ether_ntoa(&eth_addr));
145 (void) write(ep->eth_fd, &rarp46, sizeof(rarp46));
148 static int addhostname(char *addname, char *hostname, int n)
150 /* Create an additional hostname for a given hostname by adding "-n" to
151 * the first part. E.g. given "wombat.cs.vu.nl" and n=2 return
152 * "wombat-2.cs.vu.nl". This is useful for VU practical work where
153 * people get a few extra ethernet addresses on a machine and are asked
154 * to build a TCP/IP stack on it.
156 char *dot;
158 if (strlen(hostname) + 4 >= 1024) return 0;
159 if ((dot= strchr(hostname, '.')) == NULL) dot= strchr(hostname, 0);
160 sprintf(addname, "%.*s-%d%s", (dot - hostname), hostname, n, dot);
161 return 1;
164 static void usage(void)
166 fprintf(stderr, "Usage: %s [-d[level]] network-name ...\n", program);
167 exit(1);
170 static int ifname2n(const char *name)
172 /* Translate an interface name, ip0, ip1, etc, to a number. */
173 const char *np;
174 char *end;
175 unsigned long n;
177 np= name;
178 if (*np++ != 'i' || *np++ != 'p') usage();
179 n= strtoul(np, &end, 10);
180 if (end == np || *end != 0) usage();
181 if (n >= 1000) {
182 fprintf(stderr, "%s: Network number of \"%s\" is a bit large\n",
183 program, name);
184 exit(1);
186 return n;
189 int main(int argc, char **argv)
191 int i;
192 ethernet_t *ep;
193 nwio_ethopt_t ethopt;
194 nwio_ethstat_t ethstat;
195 char hostname[1024];
196 struct hostent *hostent;
197 struct sigaction sa;
198 nwio_ipconf_t ipconf;
199 asynchio_t asyn;
200 ssize_t n;
201 ipaddr_t ip_addr;
202 rarp46_t rarp46;
203 int fd;
204 int n_eths;
206 program= argv[0];
207 asyn_init(&asyn);
209 debug= 0;
210 i= 1;
211 while (i < argc && argv[i][0] == '-') {
212 char *opt= argv[i++]+1;
214 if (opt[0] == '-' && opt[1] == 0) break; /* -- */
216 while (*opt != 0) switch (*opt++) {
217 case 'd':
218 debug= 1;
219 if (between('0', *opt, '9')) debug= strtoul(opt, &opt, 10);
220 break;
221 default:
222 usage();
226 if ((n_eths= (argc - i)) == 0) usage();
228 #if __minix_vmd
229 /* Minix-vmd can handle all nets at once using async I/O. */
230 ethernets= allocate(n_eths * sizeof(ethernets[0]));
231 for (i= 0; i < n_eths; i++) {
232 ethernets[i].n= ifname2n(argv[argc - n_eths + i]);
234 #else
235 /* Minix forks n-1 times to handle each net in a process each. */
236 for (i= 0; i < n_eths; i++) {
237 if (i+1 < n_eths) {
238 switch (fork()) {
239 case -1: fatal("fork()");
240 case 0: break;
241 default: continue;
244 ethernets= allocate(1 * sizeof(ethernets[0]));
245 ethernets[0].n= ifname2n(argv[argc - n_eths + i]);
247 n_eths= 1;
248 #endif
250 sa.sa_handler= onsig;
251 sigemptyset(&sa.sa_mask);
252 sa.sa_flags= 0;
253 sigaction(SIGUSR1, &sa, NULL);
254 sigaction(SIGUSR2, &sa, NULL);
256 for (i= 0; i < n_eths; i++) {
257 ep= &ethernets[i];
258 if ((ep->eth_fd= open(ethdev(ep->n), O_RDWR)) < 0) fatal(ethdev(ep->n));
260 if (ioctl(ep->eth_fd, NWIOGETHSTAT, &ethstat) < 0) {
261 fprintf(stderr, "%s: %s: Unable to get eth statistics: %s\n",
262 program, ethdev(ep->n), strerror(errno));
263 exit(1);
265 ep->eth_addr= ethstat.nwes_addr;
266 if (debug >= 1) {
267 printf("%s: Ethernet address is %s\n",
268 ethdev(ep->n), ether_ntoa(&ep->eth_addr));
271 ethopt.nweo_flags= NWEO_COPY | NWEO_EN_LOC | NWEO_EN_BROAD |
272 NWEO_TYPESPEC;
273 ethopt.nweo_type= HTONS(ETH_RARP_PROTO);
275 if (ioctl(ep->eth_fd, NWIOSETHOPT, &ethopt) < 0) {
276 fprintf(stderr, "%s: %s: Unable to set eth options: %s\n",
277 program, ethdev(ep->n), strerror(errno));
278 exit(1);
281 /* What are my address and netmask? */
282 if ((fd= open(ipdev(ep->n), O_RDWR)) < 0) fatal(ipdev(ep->n));
283 if (ioctl(fd, NWIOGIPCONF, &ipconf) < 0) fatal(ipdev(ep->n));
285 ep->ip_addr= ipconf.nwic_ipaddr;
286 ep->ip_mask= ipconf.nwic_netmask;
287 close(fd);
288 if (debug >= 1) {
289 printf("%s: IP address is %s / ",
290 ipdev(ep->n), inet_ntoa(ep->ip_addr));
291 printf("%s\n", inet_ntoa(ep->ip_mask));
295 /* Wait for RARP requests, reply, repeat. */
296 for(;;) {
297 fflush(NULL);
299 /* Wait for a RARP request. */
300 for (i= 0; i < n_eths; i++) {
301 ep= &ethernets[i];
303 n= asyn_read(&asyn, ep->eth_fd, ep->packet, sizeof(ep->packet));
304 if (n != -1) break;
305 if (errno != EINPROGRESS) {
306 report(ethdev(ep->n));
307 sleep(10);
311 /* RARP request? */
312 if (i < n_eths
313 && n >= sizeof(rarp46)
314 && (memcpy(&rarp46, ep->packet, sizeof(rarp46)), 1)
315 && rarp46.a46_hdr == HTONS(RARP_ETHERNET)
316 && rarp46.a46_pro == HTONS(ETH_IP_PROTO)
317 && rarp46.a46_hln == 6
318 && rarp46.a46_pln == 4
319 && rarp46.a46_op == HTONS(RARP_REQUEST)
321 if ((ether_ntohost(hostname, &rarp46.a46_tha) == 0
322 || (rarp46.a46_tha.ea_addr[0] == 'v'
323 && (memcpy(&ip_addr, rarp46.a46_tha.ea_addr+2, 4), 1)
324 && (hostent= gethostbyaddr((char*) &ip_addr,
325 4, AF_INET)) != NULL
326 && addhostname(hostname, hostent->h_name,
327 rarp46.a46_tha.ea_addr[1])))
328 && (hostent= gethostbyname(hostname)) != NULL
329 && hostent->h_addrtype == AF_INET
331 /* Host is found in the ethers file and the DNS, or the
332 * ethernet address denotes a special additional address
333 * used for implementing a TCP/IP stack in user space.
335 for (i= 0; hostent->h_addr_list[i] != NULL; i++) {
336 memcpy(&ip_addr, hostent->h_addr_list[i], sizeof(ipaddr_t));
338 /* Check if the address is on this network. */
339 if (((ip_addr ^ ep->ip_addr) & ep->ip_mask) == 0) break;
342 if (hostent->h_addr_list[i] != NULL) {
343 rarp_reply(ep, hostname, ip_addr, rarp46.a46_tha);
344 } else {
345 if (debug >= 2) {
346 printf("%s: Host '%s' (%s) is on the wrong net\n",
347 ethdev(ep->n),
348 hostname, ether_ntoa(&rarp46.a46_tha));
351 } else {
352 if (debug >= 2) {
353 printf("%s: RARP request from unknown host '%s'\n",
354 ethdev(ep->n), ether_ntoa(&rarp46.a46_tha));
359 /* Wait for another request. */
360 if (asyn_wait(&asyn, 0, NULL) < 0) {
361 report("asyn_wait()");
362 sleep(10);