source: trunk/minix/commands/simple/rarpd.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 9.0 KB
Line 
1/*
2rarpd.c
3
4Created: Nov 12, 1992 by Philip Homburg
5
6Changed: May 13, 1995 by Kees J. Bot
7 Rewrite to handle multiple ethernets.
8
9Changed: Jul 18, 1995 by Kees J. Bot
10 Do RARP requests (formerly inet's job)
11
12Changed: Dec 14, 1996 by Kees J. Bot
13 Query the netmask
14
15Changed: Dec 11, 2000 by Kees J. Bot
16 Dressed down to be only a RARP server, giving the floor to DHCP
17*/
18
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>
39
40#define MAX_RARP_RETRIES 5
41#define RARP_TIMEOUT 5
42
43typedef struct rarp46
44{
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;
57
58#define ETH_RARP_PROTO 0x8035
59
60#define RARP_ETHERNET 1
61
62#define RARP_REQUEST 3
63#define RARP_REPLY 4
64
65static char *program;
66static unsigned debug;
67
68#define between(a, c, z) ((unsigned) (c) - (a) <= (unsigned) (z) - (a))
69
70static void report(const char *label)
71{
72 fprintf(stderr, "%s: %s: %s\n", program, label, strerror(errno));
73}
74
75static void fatal(const char *label)
76{
77 report(label);
78 exit(1);
79}
80
81static void *allocate(size_t size)
82{
83 void *mem;
84
85 if ((mem= malloc(size)) == NULL) fatal("Can't allocate memory");
86 return mem;
87}
88
89static char *ethdev(int n)
90{
91 static char an_ethdev[]= "/dev/ethNNN";
92
93 sprintf(an_ethdev + sizeof(an_ethdev)-4, "%d", n);
94 return an_ethdev;
95}
96
97static char *ipdev(int n)
98{
99 static char an_ipdev[]= "/dev/ipNNN";
100
101 sprintf(an_ipdev + sizeof(an_ipdev)-4, "%d", n);
102 return an_ipdev;
103}
104
105typedef 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;
113
114static ethernet_t *ethernets;
115
116static void onsig(int sig)
117{
118 switch (sig) {
119 case SIGUSR1: debug++; break;
120 case SIGUSR2: debug= 0; break;
121 }
122}
123
124static void rarp_reply(ethernet_t *ep, char *hostname, ipaddr_t ip_addr,
125 ether_addr_t eth_addr)
126{
127 rarp46_t rarp46;
128
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));
140
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));
144 }
145 (void) write(ep->eth_fd, &rarp46, sizeof(rarp46));
146}
147
148static int addhostname(char *addname, char *hostname, int n)
149{
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.
155 */
156 char *dot;
157
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;
162}
163
164static void usage(void)
165{
166 fprintf(stderr, "Usage: %s [-d[level]] network-name ...\n", program);
167 exit(1);
168}
169
170static int ifname2n(const char *name)
171{
172 /* Translate an interface name, ip0, ip1, etc, to a number. */
173 const char *np;
174 char *end;
175 unsigned long n;
176
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);
185 }
186 return n;
187}
188
189int main(int argc, char **argv)
190{
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;
205
206 program= argv[0];
207 asyn_init(&asyn);
208
209 debug= 0;
210 i= 1;
211 while (i < argc && argv[i][0] == '-') {
212 char *opt= argv[i++]+1;
213
214 if (opt[0] == '-' && opt[1] == 0) break; /* -- */
215
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();
223 }
224 }
225
226 if ((n_eths= (argc - i)) == 0) usage();
227
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]);
233 }
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;
242 }
243 }
244 ethernets= allocate(1 * sizeof(ethernets[0]));
245 ethernets[0].n= ifname2n(argv[argc - n_eths + i]);
246 }
247 n_eths= 1;
248#endif
249
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);
255
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));
259
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);
264 }
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));
269 }
270
271 ethopt.nweo_flags= NWEO_COPY | NWEO_EN_LOC | NWEO_EN_BROAD |
272 NWEO_TYPESPEC;
273 ethopt.nweo_type= HTONS(ETH_RARP_PROTO);
274
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);
279 }
280
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));
284
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));
292 }
293 }
294
295 /* Wait for RARP requests, reply, repeat. */
296 for(;;) {
297 fflush(NULL);
298
299 /* Wait for a RARP request. */
300 for (i= 0; i < n_eths; i++) {
301 ep= &ethernets[i];
302
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);
308 }
309 }
310
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)
320 ) {
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
330 ) {
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.
334 */
335 for (i= 0; hostent->h_addr_list[i] != NULL; i++) {
336 memcpy(&ip_addr, hostent->h_addr_list[i], sizeof(ipaddr_t));
337
338 /* Check if the address is on this network. */
339 if (((ip_addr ^ ep->ip_addr) & ep->ip_mask) == 0) break;
340 }
341
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));
349 }
350 }
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));
355 }
356 }
357 }
358
359 /* Wait for another request. */
360 if (asyn_wait(&asyn, 0, NULL) < 0) {
361 report("asyn_wait()");
362 sleep(10);
363 }
364 }
365}
Note: See TracBrowser for help on using the repository browser.