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
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>
28 #include <sys/asynchio.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
50 ether_addr_t a46_dstaddr
;
51 ether_addr_t a46_srcaddr
;
52 ether_type_t a46_ethtype
;
53 u16_t a46_hdr
, a46_pro
;
54 u8_t a46_hln
, a46_pln
;
60 char a46_padding
[ETH_MIN_PACK_SIZE
- (4*6 + 2*4 + 4*2 + 2*1)];
63 #define ETH_RARP_PROTO 0x8035
65 #define RARP_ETHERNET 1
67 #define RARP_REQUEST 3
71 static unsigned debug
;
73 #define between(a, c, z) ((unsigned) (c) - (a) <= (unsigned) (z) - (a))
75 static void report(const char *label
)
77 fprintf(stderr
, "%s: %s: %s\n", program
, label
, strerror(errno
));
80 static void fatal(const char *label
)
86 static void *allocate(size_t size
)
90 if ((mem
= malloc(size
)) == NULL
) fatal("Can't allocate memory");
94 static char *ethdev(int n
)
96 static char an_ethdev
[]= "/dev/ethNNN";
98 sprintf(an_ethdev
+ sizeof(an_ethdev
)-4, "%d", n
);
102 static char *ipdev(int n
)
104 static char an_ipdev
[]= "/dev/ipNNN";
106 sprintf(an_ipdev
+ sizeof(an_ipdev
)-4, "%d", n
);
110 typedef struct ethernet
{
111 int n
; /* Network number. */
112 int eth_fd
; /* Open low level ethernet device. */
113 ether_addr_t eth_addr
; /* Ethernet address of this net. */
114 char packet
[ETH_MAX_PACK_SIZE
]; /* Incoming packet. */
115 ipaddr_t ip_addr
; /* IP address of this net. */
116 ipaddr_t ip_mask
; /* Associated netmask. */
119 static ethernet_t
*ethernets
;
121 static void onsig(int sig
)
124 case SIGUSR1
: debug
++; break;
125 case SIGUSR2
: debug
= 0; break;
129 static void rarp_reply(ethernet_t
*ep
, char *hostname
, ipaddr_t ip_addr
,
130 ether_addr_t eth_addr
)
134 /* Construct a RARP reply packet and send it. */
135 rarp46
.a46_dstaddr
= eth_addr
;
136 rarp46
.a46_hdr
= HTONS(RARP_ETHERNET
);
137 rarp46
.a46_pro
= HTONS(ETH_IP_PROTO
);
140 rarp46
.a46_op
= HTONS(RARP_REPLY
);
141 rarp46
.a46_sha
= ep
->eth_addr
;
142 memcpy(rarp46
.a46_spa
, &ep
->ip_addr
, sizeof(ipaddr_t
));
143 rarp46
.a46_tha
= eth_addr
;
144 memcpy(rarp46
.a46_tpa
, &ip_addr
, sizeof(ipaddr_t
));
147 printf("%s: Replying %s (%s) to %s\n",
148 ethdev(ep
->n
), inet_ntoa(ip_addr
), hostname
, ether_ntoa(ð_addr
));
150 (void) write(ep
->eth_fd
, &rarp46
, sizeof(rarp46
));
153 static int addhostname(char *addname
, char *hostname
, int n
)
155 /* Create an additional hostname for a given hostname by adding "-n" to
156 * the first part. E.g. given "wombat.cs.vu.nl" and n=2 return
157 * "wombat-2.cs.vu.nl". This is useful for VU practical work where
158 * people get a few extra ethernet addresses on a machine and are asked
159 * to build a TCP/IP stack on it.
163 if (strlen(hostname
) + 4 >= 1024) return 0;
164 if ((dot
= strchr(hostname
, '.')) == NULL
) dot
= strchr(hostname
, 0);
165 sprintf(addname
, "%.*s-%d%s", (dot
- hostname
), hostname
, n
, dot
);
169 static void usage(void)
171 fprintf(stderr
, "Usage: %s [-d[level]] network-name ...\n", program
);
175 static int ifname2n(const char *name
)
177 /* Translate an interface name, ip0, ip1, etc, to a number. */
183 if (*np
++ != 'i' || *np
++ != 'p') usage();
184 n
= strtoul(np
, &end
, 10);
185 if (end
== np
|| *end
!= 0) usage();
187 fprintf(stderr
, "%s: Network number of \"%s\" is a bit large\n",
194 int main(int argc
, char **argv
)
198 nwio_ethopt_t ethopt
;
199 nwio_ethstat_t ethstat
;
201 struct hostent
*hostent
;
203 nwio_ipconf_t ipconf
;
216 while (i
< argc
&& argv
[i
][0] == '-') {
217 char *opt
= argv
[i
++]+1;
219 if (opt
[0] == '-' && opt
[1] == 0) break; /* -- */
221 while (*opt
!= 0) switch (*opt
++) {
224 if (between('0', *opt
, '9')) debug
= strtoul(opt
, &opt
, 10);
231 if ((n_eths
= (argc
- i
)) == 0) usage();
234 /* Minix-vmd can handle all nets at once using async I/O. */
235 ethernets
= allocate(n_eths
* sizeof(ethernets
[0]));
236 for (i
= 0; i
< n_eths
; i
++) {
237 ethernets
[i
].n
= ifname2n(argv
[argc
- n_eths
+ i
]);
240 /* Minix forks n-1 times to handle each net in a process each. */
241 for (i
= 0; i
< n_eths
; i
++) {
244 case -1: fatal("fork()");
249 ethernets
= allocate(1 * sizeof(ethernets
[0]));
250 ethernets
[0].n
= ifname2n(argv
[argc
- n_eths
+ i
]);
255 sa
.sa_handler
= onsig
;
256 sigemptyset(&sa
.sa_mask
);
258 sigaction(SIGUSR1
, &sa
, NULL
);
259 sigaction(SIGUSR2
, &sa
, NULL
);
261 for (i
= 0; i
< n_eths
; i
++) {
263 if ((ep
->eth_fd
= open(ethdev(ep
->n
), O_RDWR
)) < 0) fatal(ethdev(ep
->n
));
265 if (ioctl(ep
->eth_fd
, NWIOGETHSTAT
, ðstat
) < 0) {
266 fprintf(stderr
, "%s: %s: Unable to get eth statistics: %s\n",
267 program
, ethdev(ep
->n
), strerror(errno
));
270 ep
->eth_addr
= ethstat
.nwes_addr
;
272 printf("%s: Ethernet address is %s\n",
273 ethdev(ep
->n
), ether_ntoa(&ep
->eth_addr
));
276 ethopt
.nweo_flags
= NWEO_COPY
| NWEO_EN_LOC
| NWEO_EN_BROAD
|
278 ethopt
.nweo_type
= HTONS(ETH_RARP_PROTO
);
280 if (ioctl(ep
->eth_fd
, NWIOSETHOPT
, ðopt
) < 0) {
281 fprintf(stderr
, "%s: %s: Unable to set eth options: %s\n",
282 program
, ethdev(ep
->n
), strerror(errno
));
286 /* What are my address and netmask? */
287 if ((fd
= open(ipdev(ep
->n
), O_RDWR
)) < 0) fatal(ipdev(ep
->n
));
288 if (ioctl(fd
, NWIOGIPCONF
, &ipconf
) < 0) fatal(ipdev(ep
->n
));
290 ep
->ip_addr
= ipconf
.nwic_ipaddr
;
291 ep
->ip_mask
= ipconf
.nwic_netmask
;
294 printf("%s: IP address is %s / ",
295 ipdev(ep
->n
), inet_ntoa(ep
->ip_addr
));
296 printf("%s\n", inet_ntoa(ep
->ip_mask
));
300 /* Wait for RARP requests, reply, repeat. */
304 /* Wait for a RARP request. */
305 for (i
= 0; i
< n_eths
; i
++) {
308 n
= asyn_read(&asyn
, ep
->eth_fd
, ep
->packet
, sizeof(ep
->packet
));
310 if (errno
!= EINPROGRESS
) {
311 report(ethdev(ep
->n
));
318 && n
>= sizeof(rarp46
)
319 && (memcpy(&rarp46
, ep
->packet
, sizeof(rarp46
)), 1)
320 && rarp46
.a46_hdr
== HTONS(RARP_ETHERNET
)
321 && rarp46
.a46_pro
== HTONS(ETH_IP_PROTO
)
322 && rarp46
.a46_hln
== 6
323 && rarp46
.a46_pln
== 4
324 && rarp46
.a46_op
== HTONS(RARP_REQUEST
)
326 if ((ether_ntohost(hostname
, &rarp46
.a46_tha
) == 0
327 || (rarp46
.a46_tha
.ea_addr
[0] == 'v'
328 && (memcpy(&ip_addr
, rarp46
.a46_tha
.ea_addr
+2, 4), 1)
329 && (hostent
= gethostbyaddr((char*) &ip_addr
,
331 && addhostname(hostname
, hostent
->h_name
,
332 rarp46
.a46_tha
.ea_addr
[1])))
333 && (hostent
= gethostbyname(hostname
)) != NULL
334 && hostent
->h_addrtype
== AF_INET
336 /* Host is found in the ethers file and the DNS, or the
337 * ethernet address denotes a special additional address
338 * used for implementing a TCP/IP stack in user space.
340 for (i
= 0; hostent
->h_addr_list
[i
] != NULL
; i
++) {
341 memcpy(&ip_addr
, hostent
->h_addr_list
[i
], sizeof(ipaddr_t
));
343 /* Check if the address is on this network. */
344 if (((ip_addr
^ ep
->ip_addr
) & ep
->ip_mask
) == 0) break;
347 if (hostent
->h_addr_list
[i
] != NULL
) {
348 rarp_reply(ep
, hostname
, ip_addr
, rarp46
.a46_tha
);
351 printf("%s: Host '%s' (%s) is on the wrong net\n",
353 hostname
, ether_ntoa(&rarp46
.a46_tha
));
358 printf("%s: RARP request from unknown host '%s'\n",
359 ethdev(ep
->n
), ether_ntoa(&rarp46
.a46_tha
));
364 /* Wait for another request. */
365 if (asyn_wait(&asyn
, 0, NULL
) < 0) {
366 report("asyn_wait()");