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
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
;
55 char a46_padding
[ETH_MIN_PACK_SIZE
- (4*6 + 2*4 + 4*2 + 2*1)];
58 #define ETH_RARP_PROTO 0x8035
60 #define RARP_ETHERNET 1
62 #define RARP_REQUEST 3
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
)
81 static void *allocate(size_t size
)
85 if ((mem
= malloc(size
)) == NULL
) fatal("Can't allocate memory");
89 static char *ethdev(int n
)
91 static char an_ethdev
[]= "/dev/ethNNN";
93 sprintf(an_ethdev
+ sizeof(an_ethdev
)-4, "%d", n
);
97 static char *ipdev(int n
)
99 static char an_ipdev
[]= "/dev/ipNNN";
101 sprintf(an_ipdev
+ sizeof(an_ipdev
)-4, "%d", n
);
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. */
114 static ethernet_t
*ethernets
;
116 static void onsig(int 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
)
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
);
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
));
142 printf("%s: Replying %s (%s) to %s\n",
143 ethdev(ep
->n
), inet_ntoa(ip_addr
), hostname
, ether_ntoa(ð_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.
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
);
164 static void usage(void)
166 fprintf(stderr
, "Usage: %s [-d[level]] network-name ...\n", program
);
170 static int ifname2n(const char *name
)
172 /* Translate an interface name, ip0, ip1, etc, to a number. */
178 if (*np
++ != 'i' || *np
++ != 'p') usage();
179 n
= strtoul(np
, &end
, 10);
180 if (end
== np
|| *end
!= 0) usage();
182 fprintf(stderr
, "%s: Network number of \"%s\" is a bit large\n",
189 int main(int argc
, char **argv
)
193 nwio_ethopt_t ethopt
;
194 nwio_ethstat_t ethstat
;
196 struct hostent
*hostent
;
198 nwio_ipconf_t ipconf
;
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
++) {
219 if (between('0', *opt
, '9')) debug
= strtoul(opt
, &opt
, 10);
226 if ((n_eths
= (argc
- i
)) == 0) usage();
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
]);
235 /* Minix forks n-1 times to handle each net in a process each. */
236 for (i
= 0; i
< n_eths
; i
++) {
239 case -1: fatal("fork()");
244 ethernets
= allocate(1 * sizeof(ethernets
[0]));
245 ethernets
[0].n
= ifname2n(argv
[argc
- n_eths
+ i
]);
250 sa
.sa_handler
= onsig
;
251 sigemptyset(&sa
.sa_mask
);
253 sigaction(SIGUSR1
, &sa
, NULL
);
254 sigaction(SIGUSR2
, &sa
, NULL
);
256 for (i
= 0; i
< n_eths
; i
++) {
258 if ((ep
->eth_fd
= open(ethdev(ep
->n
), O_RDWR
)) < 0) fatal(ethdev(ep
->n
));
260 if (ioctl(ep
->eth_fd
, NWIOGETHSTAT
, ðstat
) < 0) {
261 fprintf(stderr
, "%s: %s: Unable to get eth statistics: %s\n",
262 program
, ethdev(ep
->n
), strerror(errno
));
265 ep
->eth_addr
= ethstat
.nwes_addr
;
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
|
273 ethopt
.nweo_type
= HTONS(ETH_RARP_PROTO
);
275 if (ioctl(ep
->eth_fd
, NWIOSETHOPT
, ðopt
) < 0) {
276 fprintf(stderr
, "%s: %s: Unable to set eth options: %s\n",
277 program
, ethdev(ep
->n
), strerror(errno
));
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
;
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. */
299 /* Wait for a RARP request. */
300 for (i
= 0; i
< n_eths
; i
++) {
303 n
= asyn_read(&asyn
, ep
->eth_fd
, ep
->packet
, sizeof(ep
->packet
));
305 if (errno
!= EINPROGRESS
) {
306 report(ethdev(ep
->n
));
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
,
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
);
346 printf("%s: Host '%s' (%s) is on the wrong net\n",
348 hostname
, ether_ntoa(&rarp46
.a46_tha
));
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()");