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>
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
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
;
58 char a46_padding
[ETH_MIN_PACK_SIZE
- (4*6 + 2*4 + 4*2 + 2*1)];
61 #define ETH_RARP_PROTO 0x8035
63 #define RARP_ETHERNET 1
65 #define RARP_REQUEST 3
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
)
84 static void *allocate(size_t size
)
88 if ((mem
= malloc(size
)) == NULL
) fatal("Can't allocate memory");
92 static char *ethdev(int n
)
94 static char an_ethdev
[]= "/dev/ethNNN";
96 sprintf(an_ethdev
+ sizeof(an_ethdev
)-4, "%d", n
);
100 static char *ipdev(int n
)
102 static char an_ipdev
[]= "/dev/ipNNN";
104 sprintf(an_ipdev
+ sizeof(an_ipdev
)-4, "%d", n
);
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. */
117 static ethernet_t
*ethernets
;
119 static void onsig(int 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
)
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
);
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
));
145 printf("%s: Replying %s (%s) to %s\n",
146 ethdev(ep
->n
), inet_ntoa(ip_addr
), hostname
, ether_ntoa(ð_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.
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
);
167 static void usage(void)
169 fprintf(stderr
, "Usage: %s [-d[level]] network-name ...\n", program
);
173 static int ifname2n(const char *name
)
175 /* Translate an interface name, ip0, ip1, etc, to a number. */
181 if (*np
++ != 'i' || *np
++ != 'p') usage();
182 n
= strtoul(np
, &end
, 10);
183 if (end
== np
|| *end
!= 0) usage();
185 fprintf(stderr
, "%s: Network number of \"%s\" is a bit large\n",
192 int main(int argc
, char **argv
)
196 nwio_ethopt_t ethopt
;
197 nwio_ethstat_t ethstat
;
199 struct hostent
*hostent
;
201 nwio_ipconf_t ipconf
;
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
++) {
222 if (between('0', *opt
, '9')) debug
= strtoul(opt
, &opt
, 10);
229 if ((n_eths
= (argc
- i
)) == 0) usage();
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
]);
238 /* Minix forks n-1 times to handle each net in a process each. */
239 for (i
= 0; i
< n_eths
; i
++) {
242 case -1: fatal("fork()");
247 ethernets
= allocate(1 * sizeof(ethernets
[0]));
248 ethernets
[0].n
= ifname2n(argv
[argc
- n_eths
+ i
]);
253 sa
.sa_handler
= onsig
;
254 sigemptyset(&sa
.sa_mask
);
256 sigaction(SIGUSR1
, &sa
, NULL
);
257 sigaction(SIGUSR2
, &sa
, NULL
);
259 for (i
= 0; i
< n_eths
; i
++) {
261 if ((ep
->eth_fd
= open(ethdev(ep
->n
), O_RDWR
)) < 0) fatal(ethdev(ep
->n
));
263 if (ioctl(ep
->eth_fd
, NWIOGETHSTAT
, ðstat
) < 0) {
264 fprintf(stderr
, "%s: %s: Unable to get eth statistics: %s\n",
265 program
, ethdev(ep
->n
), strerror(errno
));
268 ep
->eth_addr
= ethstat
.nwes_addr
;
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
|
276 ethopt
.nweo_type
= HTONS(ETH_RARP_PROTO
);
278 if (ioctl(ep
->eth_fd
, NWIOSETHOPT
, ðopt
) < 0) {
279 fprintf(stderr
, "%s: %s: Unable to set eth options: %s\n",
280 program
, ethdev(ep
->n
), strerror(errno
));
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
;
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. */
302 /* Wait for a RARP request. */
303 for (i
= 0; i
< n_eths
; i
++) {
306 n
= asyn_read(&asyn
, ep
->eth_fd
, ep
->packet
, sizeof(ep
->packet
));
308 if (errno
!= EINPROGRESS
) {
309 report(ethdev(ep
->n
));
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
,
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
);
349 printf("%s: Host '%s' (%s) is on the wrong net\n",
351 hostname
, ether_ntoa(&rarp46
.a46_tha
));
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()");