Mercurial > illumos > onarm
comparison usr/src/cmd/cmd-inet/usr.sbin/in.rarpd.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c9caec207d52 |
---|---|
1 /* | |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
5 * Common Development and Distribution License (the "License"). | |
6 * You may not use this file except in compliance with the License. | |
7 * | |
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 * or http://www.opensolaris.org/os/licensing. | |
10 * See the License for the specific language governing permissions | |
11 * and limitations under the License. | |
12 * | |
13 * When distributing Covered Code, include this CDDL HEADER in each | |
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 * If applicable, add the following below this CDDL HEADER, with the | |
16 * fields enclosed by brackets "[]" replaced with your own identifying | |
17 * information: Portions Copyright [yyyy] [name of copyright owner] | |
18 * | |
19 * CDDL HEADER END | |
20 */ | |
21 /* | |
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | |
23 * Use is subject to license terms. | |
24 */ | |
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ | |
26 /* All Rights Reserved */ | |
27 | |
28 /* | |
29 * Portions of this source code were derived from Berkeley 4.3 BSD | |
30 * under license from the Regents of the University of California. | |
31 */ | |
32 | |
33 #pragma ident "@(#)in.rarpd.c 1.39 07/06/12 SMI" | |
34 | |
35 /* | |
36 * rarpd.c Reverse-ARP server. | |
37 * Refer to RFC 903 "A Reverse Address Resolution Protocol". | |
38 */ | |
39 | |
40 #define _REENTRANT | |
41 | |
42 #include <thread.h> | |
43 #include <synch.h> | |
44 #include <stdlib.h> | |
45 #include <unistd.h> | |
46 #include <sys/resource.h> | |
47 #include <stdio.h> | |
48 #include <stdio_ext.h> | |
49 #include <stdarg.h> | |
50 #include <string.h> | |
51 #include <fcntl.h> | |
52 #include <sys/types.h> | |
53 #include <dirent.h> | |
54 #include <syslog.h> | |
55 #include <netdb.h> | |
56 #include <errno.h> | |
57 #include <sys/socket.h> | |
58 #include <sys/sockio.h> | |
59 #include <net/if.h> | |
60 #include <netinet/if_ether.h> | |
61 #include <netinet/in.h> | |
62 #include <arpa/inet.h> | |
63 #include <stropts.h> | |
64 #include <libinetutil.h> | |
65 #include <libdlpi.h> | |
66 #include <net/if_types.h> | |
67 #include <net/if_dl.h> | |
68 | |
69 #define BOOTDIR "/tftpboot" /* boot files directory */ | |
70 #define DEVIP "/dev/ip" /* path to ip driver */ | |
71 #define DEVARP "/dev/arp" /* path to arp driver */ | |
72 | |
73 #define BUFSIZE 2048 /* max receive frame length */ | |
74 #define MAXPATHL 128 /* max path length */ | |
75 #define MAXHOSTL 128 /* max host name length */ | |
76 #define MAXIFS 256 | |
77 | |
78 /* | |
79 * Logical network devices | |
80 */ | |
81 struct ifdev { | |
82 char ldevice[IFNAMSIZ]; | |
83 int lunit; | |
84 ipaddr_t ipaddr; /* network order */ | |
85 ipaddr_t if_netmask; /* host order */ | |
86 ipaddr_t if_ipaddr; /* host order */ | |
87 ipaddr_t if_netnum; /* host order, with subnet */ | |
88 struct ifdev *next; | |
89 }; | |
90 | |
91 /* | |
92 * Physical network device | |
93 */ | |
94 struct rarpdev { | |
95 char device[DLPI_LINKNAME_MAX]; | |
96 uint_t unit; | |
97 dlpi_handle_t dh_rarp; | |
98 uchar_t physaddr[DLPI_PHYSADDR_MAX]; | |
99 /* mac address of interface */ | |
100 uint_t physaddrlen; /* mac address length */ | |
101 int ifrarplen; /* size of rarp data packet */ | |
102 struct ifdev *ifdev; /* private interface info */ | |
103 struct rarpdev *next; /* list of managed devices */ | |
104 }; | |
105 | |
106 struct rarpreply { | |
107 struct rarpdev *rdev; /* which device reply for */ | |
108 struct timeval tv; /* send RARP reply by when */ | |
109 uchar_t *lldest; /* target mac to send reply */ | |
110 uchar_t *arprep; /* [R]ARP response */ | |
111 struct rarpreply *next; | |
112 }; | |
113 | |
114 static struct rarpreply *delay_list; | |
115 static sema_t delay_sema; | |
116 static mutex_t delay_mutex; | |
117 static mutex_t debug_mutex; | |
118 | |
119 static struct rarpdev *rarpdev_head; | |
120 | |
121 /* | |
122 * Globals initialized before multi-threading | |
123 */ | |
124 static char *cmdname; /* command name from argv[0] */ | |
125 static int dflag = 0; /* enable diagnostics */ | |
126 static int aflag = 0; /* start rarpd on all interfaces */ | |
127 | |
128 static void getintf(void); | |
129 static struct rarpdev *find_device(ifspec_t *); | |
130 static void init_rarpdev(struct rarpdev *); | |
131 static void do_rarp(void *); | |
132 static void rarp_request(struct rarpdev *, struct arphdr *, | |
133 uchar_t *); | |
134 static void add_arp(struct rarpdev *, uchar_t *, uchar_t *); | |
135 static void arp_request(struct rarpdev *, struct arphdr *, uchar_t *); | |
136 static void do_delay_write(void *); | |
137 static void delay_write(struct rarpdev *, struct rarpreply *); | |
138 static int mightboot(ipaddr_t); | |
139 static void get_ifdata(char *, int, ipaddr_t *, ipaddr_t *); | |
140 static int get_ipaddr(struct rarpdev *, uchar_t *, uchar_t *, ipaddr_t *); | |
141 static int strioctl(int, int, int, int, char *); | |
142 static void usage(); | |
143 static void syserr(const char *); | |
144 /*PRINTFLIKE1*/ | |
145 static void error(const char *, ...); | |
146 static void debug(char *, ...); | |
147 | |
148 extern int optind; | |
149 extern char *optarg; | |
150 | |
151 int | |
152 main(int argc, char *argv[]) | |
153 { | |
154 int c; | |
155 struct rlimit rl; | |
156 struct rarpdev *rdev; | |
157 int i; | |
158 | |
159 cmdname = argv[0]; | |
160 | |
161 while ((c = getopt(argc, argv, "ad")) != -1) { | |
162 switch (c) { | |
163 case 'a': | |
164 aflag = 1; | |
165 break; | |
166 | |
167 case 'd': | |
168 dflag = 1; | |
169 break; | |
170 | |
171 default: | |
172 usage(); | |
173 } | |
174 } | |
175 | |
176 if ((!aflag && (argc - optind) != 2) || | |
177 (aflag && (argc - optind) != 0)) { | |
178 usage(); | |
179 /* NOTREACHED */ | |
180 } | |
181 | |
182 if (!dflag) { | |
183 /* | |
184 * Background | |
185 */ | |
186 switch (fork()) { | |
187 case -1: /* error */ | |
188 syserr("fork"); | |
189 /*NOTREACHED*/ | |
190 | |
191 case 0: /* child */ | |
192 break; | |
193 | |
194 default: /* parent */ | |
195 return (0); | |
196 } | |
197 for (i = 0; i < 3; i++) { | |
198 (void) close(i); | |
199 } | |
200 (void) open("/", O_RDONLY, 0); | |
201 (void) dup2(0, 1); | |
202 (void) dup2(0, 2); | |
203 /* | |
204 * Detach terminal | |
205 */ | |
206 if (setsid() < 0) | |
207 syserr("setsid"); | |
208 } | |
209 | |
210 rl.rlim_cur = RLIM_INFINITY; | |
211 rl.rlim_max = RLIM_INFINITY; | |
212 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) | |
213 syserr("setrlimit"); | |
214 (void) enable_extended_FILE_stdio(-1, -1); | |
215 | |
216 (void) openlog(cmdname, LOG_PID, LOG_DAEMON); | |
217 | |
218 if (aflag) { | |
219 /* | |
220 * Get each interface name and load rarpdev list. | |
221 */ | |
222 getintf(); | |
223 } else { | |
224 ifspec_t ifsp; | |
225 struct ifdev *ifdev; | |
226 char buf[IFNAMSIZ + 1]; | |
227 | |
228 /* | |
229 * Load specified device as only element of the list. | |
230 */ | |
231 rarpdev_head = (struct rarpdev *)calloc(1, | |
232 sizeof (struct rarpdev)); | |
233 if (rarpdev_head == NULL) { | |
234 error("out of memory"); | |
235 } | |
236 (void) strncpy(buf, argv[optind], IFNAMSIZ); | |
237 (void) strncat(buf, argv[optind + 1], IFNAMSIZ - strlen(buf)); | |
238 | |
239 if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL) { | |
240 error("out of memory"); | |
241 } | |
242 | |
243 if (!ifparse_ifspec(buf, &ifsp) || ifsp.ifsp_modcnt != 0) { | |
244 error("invalid interface specification"); | |
245 } | |
246 | |
247 if (ifsp.ifsp_lunvalid) { | |
248 (void) snprintf(ifdev->ldevice, | |
249 sizeof (ifdev->ldevice), "%s%d:", | |
250 ifsp.ifsp_devnm, ifsp.ifsp_ppa); | |
251 ifdev->lunit = ifsp.ifsp_lun; | |
252 } else { | |
253 ifdev->lunit = -1; /* no logical unit */ | |
254 } | |
255 (void) strlcpy(rarpdev_head->device, ifsp.ifsp_devnm, | |
256 sizeof (rarpdev_head->device)); | |
257 rarpdev_head->unit = ifsp.ifsp_ppa; | |
258 | |
259 ifdev->next = rarpdev_head->ifdev; | |
260 rarpdev_head->ifdev = ifdev; | |
261 } | |
262 | |
263 /* | |
264 * Initialize each rarpdev. | |
265 */ | |
266 for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) { | |
267 init_rarpdev(rdev); | |
268 } | |
269 | |
270 (void) sema_init(&delay_sema, 0, USYNC_THREAD, NULL); | |
271 (void) mutex_init(&delay_mutex, USYNC_THREAD, NULL); | |
272 (void) mutex_init(&debug_mutex, USYNC_THREAD, NULL); | |
273 | |
274 /* | |
275 * Start delayed processing thread. | |
276 */ | |
277 (void) thr_create(NULL, NULL, (void *(*)(void *))do_delay_write, NULL, | |
278 THR_NEW_LWP, NULL); | |
279 | |
280 /* | |
281 * Start RARP processing for each device. | |
282 */ | |
283 for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) { | |
284 if (rdev->dh_rarp != NULL) { | |
285 (void) thr_create(NULL, NULL, | |
286 (void *(*)(void *))do_rarp, (void *)rdev, | |
287 THR_NEW_LWP, NULL); | |
288 } | |
289 } | |
290 | |
291 /* | |
292 * Exit main() thread | |
293 */ | |
294 thr_exit(NULL); | |
295 | |
296 return (0); | |
297 } | |
298 | |
299 static void | |
300 getintf(void) | |
301 { | |
302 int fd; | |
303 int numifs; | |
304 unsigned bufsize; | |
305 struct ifreq *reqbuf; | |
306 struct ifconf ifconf; | |
307 struct ifreq *ifr; | |
308 struct rarpdev *rdev; | |
309 struct ifdev *ifdev; | |
310 | |
311 /* | |
312 * Open the IP provider. | |
313 */ | |
314 if ((fd = open(DEVIP, 0)) < 0) | |
315 syserr(DEVIP); | |
316 | |
317 /* | |
318 * Ask IP for the list of configured interfaces. | |
319 */ | |
320 if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) { | |
321 numifs = MAXIFS; | |
322 } | |
323 bufsize = numifs * sizeof (struct ifreq); | |
324 reqbuf = (struct ifreq *)malloc(bufsize); | |
325 if (reqbuf == NULL) { | |
326 error("out of memory"); | |
327 } | |
328 | |
329 ifconf.ifc_len = bufsize; | |
330 ifconf.ifc_buf = (caddr_t)reqbuf; | |
331 if (ioctl(fd, SIOCGIFCONF, (char *)&ifconf) < 0) | |
332 syserr("SIOCGIFCONF"); | |
333 | |
334 /* | |
335 * Initialize a rarpdev for each interface. | |
336 */ | |
337 for (ifr = ifconf.ifc_req; ifconf.ifc_len > 0; | |
338 ifr++, ifconf.ifc_len -= sizeof (struct ifreq)) { | |
339 ifspec_t ifsp; | |
340 | |
341 if (ioctl(fd, SIOCGIFFLAGS, (char *)ifr) < 0) { | |
342 syserr("ioctl SIOCGIFFLAGS"); | |
343 exit(1); | |
344 } | |
345 if ((ifr->ifr_flags & IFF_LOOPBACK) || | |
346 !(ifr->ifr_flags & IFF_UP) || | |
347 !(ifr->ifr_flags & IFF_BROADCAST) || | |
348 (ifr->ifr_flags & IFF_NOARP) || | |
349 (ifr->ifr_flags & IFF_POINTOPOINT)) | |
350 continue; | |
351 | |
352 if (!ifparse_ifspec(ifr->ifr_name, &ifsp)) | |
353 error("ifparse_ifspec failed"); | |
354 | |
355 /* | |
356 * Look for an existing device for logical interfaces. | |
357 */ | |
358 if ((rdev = find_device(&ifsp)) == NULL) { | |
359 rdev = calloc(1, sizeof (struct rarpdev)); | |
360 if (rdev == NULL) | |
361 error("out of memory"); | |
362 | |
363 (void) strlcpy(rdev->device, ifsp.ifsp_devnm, | |
364 sizeof (rdev->device)); | |
365 rdev->unit = ifsp.ifsp_ppa; | |
366 | |
367 rdev->next = rarpdev_head; | |
368 rarpdev_head = rdev; | |
369 } | |
370 | |
371 if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL) | |
372 error("out of memory"); | |
373 | |
374 if (ifsp.ifsp_lunvalid) { | |
375 (void) snprintf(ifdev->ldevice, | |
376 sizeof (ifdev->ldevice), "%s%d:", | |
377 ifsp.ifsp_devnm, ifsp.ifsp_ppa); | |
378 ifdev->lunit = ifsp.ifsp_lun; | |
379 } else | |
380 ifdev->lunit = -1; /* no logical unit */ | |
381 | |
382 ifdev->next = rdev->ifdev; | |
383 rdev->ifdev = ifdev; | |
384 } | |
385 (void) free((char *)reqbuf); | |
386 } | |
387 | |
388 static struct rarpdev * | |
389 find_device(ifspec_t *specp) | |
390 { | |
391 struct rarpdev *rdev; | |
392 | |
393 for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) { | |
394 if (specp->ifsp_ppa == rdev->unit && | |
395 strcmp(specp->ifsp_devnm, rdev->device) == 0) | |
396 return (rdev); | |
397 } | |
398 return (NULL); | |
399 } | |
400 | |
401 static void | |
402 init_rarpdev(struct rarpdev *rdev) | |
403 { | |
404 char *dev; | |
405 int unit; | |
406 struct ifdev *ifdev; | |
407 int retval; | |
408 char *str = NULL; | |
409 uint_t physaddrlen = DLPI_PHYSADDR_MAX; | |
410 char linkname[DLPI_LINKNAME_MAX]; | |
411 dlpi_handle_t dh; | |
412 | |
413 (void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", rdev->device, | |
414 rdev->unit); | |
415 /* | |
416 * Open datalink provider and get our mac address. | |
417 */ | |
418 if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) { | |
419 error("cannot open link %s: %s", linkname, | |
420 dlpi_strerror(retval)); | |
421 } | |
422 | |
423 if ((retval = dlpi_bind(dh, ETHERTYPE_REVARP, NULL)) != DLPI_SUCCESS) { | |
424 dlpi_close(dh); | |
425 error("dlpi_bind failed: %s", dlpi_strerror(retval)); | |
426 } | |
427 | |
428 /* | |
429 * Save our mac address. | |
430 */ | |
431 if ((retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, rdev->physaddr, | |
432 &physaddrlen)) != DLPI_SUCCESS) { | |
433 dlpi_close(dh); | |
434 error("dlpi_get_physaddr failed: %s", dlpi_strerror(retval)); | |
435 } | |
436 | |
437 rdev->physaddrlen = physaddrlen; | |
438 rdev->ifrarplen = sizeof (struct arphdr) + (2 * sizeof (ipaddr_t)) + | |
439 (2 * physaddrlen); | |
440 | |
441 if (dflag) { | |
442 str = _link_ntoa(rdev->physaddr, str, | |
443 rdev->physaddrlen, IFT_OTHER); | |
444 if (str != NULL) { | |
445 debug("device %s physical address %s", linkname, str); | |
446 free(str); | |
447 } | |
448 } | |
449 | |
450 /* | |
451 * Assign dlpi handle to rdev. | |
452 */ | |
453 rdev->dh_rarp = dh; | |
454 | |
455 /* | |
456 * Get the IP address and netmask from directory service for | |
457 * each logical interface. | |
458 */ | |
459 for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) { | |
460 /* | |
461 * If lunit == -1 then this is the primary interface name. | |
462 */ | |
463 if (ifdev->lunit == -1) { | |
464 dev = rdev->device; | |
465 unit = rdev->unit; | |
466 } else { | |
467 dev = ifdev->ldevice; | |
468 unit = ifdev->lunit; | |
469 } | |
470 get_ifdata(dev, unit, &ifdev->if_ipaddr, &ifdev->if_netmask); | |
471 | |
472 /* | |
473 * Use IP address of the interface. | |
474 */ | |
475 ifdev->if_netnum = ifdev->if_ipaddr & ifdev->if_netmask; | |
476 ifdev->ipaddr = (ipaddr_t)htonl(ifdev->if_ipaddr); | |
477 } | |
478 } | |
479 | |
480 static void | |
481 do_rarp(void *buf) | |
482 { | |
483 struct rarpdev *rdev = buf; | |
484 char *cause; | |
485 struct arphdr *ans; | |
486 uchar_t *shost; | |
487 uint_t saddrlen; | |
488 size_t anslen = rdev->ifrarplen; | |
489 char *str = NULL; | |
490 int retval; | |
491 | |
492 if (((shost = malloc(rdev->physaddrlen)) == NULL) || | |
493 ((ans = malloc(rdev->ifrarplen)) == NULL)) | |
494 syserr("malloc"); | |
495 | |
496 if (dflag) { | |
497 str = _link_ntoa(rdev->physaddr, str, rdev->physaddrlen, | |
498 IFT_OTHER); | |
499 if (str != NULL) { | |
500 debug("starting rarp service on device %s%d physical" | |
501 " address %s", rdev->device, rdev->unit, str); | |
502 free(str); | |
503 } | |
504 } | |
505 | |
506 /* | |
507 * Read RARP packets and respond to them. | |
508 */ | |
509 for (;;) { | |
510 saddrlen = DLPI_PHYSADDR_MAX; | |
511 retval = dlpi_recv(rdev->dh_rarp, shost, | |
512 &saddrlen, ans, &anslen, -1, NULL); | |
513 if (retval == DLPI_ETIMEDOUT) { | |
514 continue; | |
515 } else if (retval != DLPI_SUCCESS) { | |
516 error("error in dlpi_recv %s: %s", rdev->dh_rarp, | |
517 dlpi_strerror(retval)); | |
518 } | |
519 | |
520 cause = NULL; | |
521 | |
522 if (anslen < rdev->ifrarplen) | |
523 cause = "short packet"; | |
524 else if (ans->ar_hrd != htons(ARPHRD_ETHER)) | |
525 cause = "hardware type not Ethernet"; | |
526 else if (ans->ar_pro != htons(ETHERTYPE_IP)) | |
527 cause = "protocol type not IP"; | |
528 else if (ans->ar_hln != rdev->physaddrlen) | |
529 cause = "unexpected hardware address length"; | |
530 else if (ans->ar_pln != sizeof (ipaddr_t)) | |
531 cause = "unexpected protocol address length"; | |
532 if (cause != NULL) { | |
533 if (dflag) | |
534 debug("RARP packet received but " | |
535 "discarded: %s", cause); | |
536 continue; | |
537 } | |
538 | |
539 /* | |
540 * Handle the request. | |
541 */ | |
542 switch (ntohs(ans->ar_op)) { | |
543 case REVARP_REQUEST: | |
544 rarp_request(rdev, ans, shost); | |
545 break; | |
546 | |
547 case ARPOP_REQUEST: | |
548 arp_request(rdev, ans, shost); | |
549 break; | |
550 | |
551 case REVARP_REPLY: | |
552 if (dflag) | |
553 debug("REVARP_REPLY ignored"); | |
554 break; | |
555 | |
556 case ARPOP_REPLY: | |
557 if (dflag) | |
558 debug("ARPOP_REPLY ignored"); | |
559 break; | |
560 | |
561 default: | |
562 if (dflag) | |
563 debug("unknown opcode 0x%x", ans->ar_op); | |
564 break; | |
565 } | |
566 } | |
567 } | |
568 | |
569 /* | |
570 * Reverse address determination and allocation code. | |
571 */ | |
572 static void | |
573 rarp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost) | |
574 { | |
575 ipaddr_t tpa, spa; | |
576 struct rarpreply *rrp; | |
577 uchar_t *shap, *thap, *spap, *tpap; | |
578 char *str = NULL; | |
579 int retval; | |
580 | |
581 shap = (uchar_t *)rp + sizeof (struct arphdr); | |
582 spap = shap + rp->ar_hln; | |
583 thap = spap + rp->ar_pln; | |
584 tpap = thap + rp->ar_hln; | |
585 | |
586 if (dflag) { | |
587 str = _link_ntoa(thap, str, rdev->physaddrlen, IFT_OTHER); | |
588 if (str != NULL) { | |
589 debug("RARP_REQUEST for %s", str); | |
590 free(str); | |
591 } | |
592 } | |
593 | |
594 /* | |
595 * Third party lookups are rare and wonderful. | |
596 */ | |
597 if ((memcmp(shap, thap, rdev->physaddrlen) != 0) || | |
598 (memcmp(shap, shost, rdev->physaddrlen) != 0)) { | |
599 if (dflag) | |
600 debug("weird (3rd party lookup)"); | |
601 } | |
602 | |
603 /* | |
604 * Fill in given parts of reply packet. | |
605 */ | |
606 (void) memcpy(shap, rdev->physaddr, rdev->physaddrlen); | |
607 | |
608 /* | |
609 * If a good address is stored in our lookup tables, return it | |
610 * immediately or after a delay. Store it in our kernel's ARP cache. | |
611 */ | |
612 if (get_ipaddr(rdev, thap, tpap, &spa)) | |
613 return; | |
614 (void) memcpy(spap, &spa, sizeof (spa)); | |
615 | |
616 add_arp(rdev, tpap, thap); | |
617 | |
618 rp->ar_op = htons(REVARP_REPLY); | |
619 | |
620 if (dflag) { | |
621 struct in_addr addr; | |
622 | |
623 (void) memcpy(&addr, tpap, sizeof (ipaddr_t)); | |
624 debug("good lookup, maps to %s", inet_ntoa(addr)); | |
625 } | |
626 | |
627 rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen + | |
628 rdev->ifrarplen); | |
629 if (rrp == NULL) | |
630 error("out of memory"); | |
631 rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply); | |
632 rrp->arprep = rrp->lldest + rdev->physaddrlen; | |
633 | |
634 /* | |
635 * Create rarpreply structure. | |
636 */ | |
637 (void) gettimeofday(&rrp->tv, NULL); | |
638 rrp->tv.tv_sec += 3; /* delay */ | |
639 rrp->rdev = rdev; | |
640 (void) memcpy(rrp->lldest, shost, rdev->physaddrlen); | |
641 (void) memcpy(rrp->arprep, rp, rdev->ifrarplen); | |
642 | |
643 /* | |
644 * If this is diskless and we're not its bootserver, let the | |
645 * bootserver reply first by delaying a while. | |
646 */ | |
647 (void) memcpy(&tpa, tpap, sizeof (ipaddr_t)); | |
648 if (mightboot(ntohl(tpa))) { | |
649 retval = dlpi_send(rdev->dh_rarp, rrp->lldest, | |
650 rdev->physaddrlen, rrp->arprep, rdev->ifrarplen, NULL); | |
651 if (retval != DLPI_SUCCESS) { | |
652 error("dlpi_send failed: %s", dlpi_strerror(retval)); | |
653 } else if (dflag) { | |
654 debug("immediate reply sent"); | |
655 } | |
656 (void) free(rrp); | |
657 } else { | |
658 delay_write(rdev, rrp); | |
659 } | |
660 } | |
661 | |
662 /* | |
663 * Download an ARP entry into our kernel. | |
664 */ | |
665 static void | |
666 add_arp(struct rarpdev *rdev, uchar_t *ip, uchar_t *laddr) | |
667 { | |
668 struct xarpreq ar; | |
669 struct sockaddr_in *sin; | |
670 int fd; | |
671 | |
672 /* | |
673 * Common part of query or set. | |
674 */ | |
675 (void) memset(&ar, 0, sizeof (ar)); | |
676 ar.xarp_pa.ss_family = AF_INET; | |
677 sin = (struct sockaddr_in *)&ar.xarp_pa; | |
678 (void) memcpy(&sin->sin_addr, ip, sizeof (ipaddr_t)); | |
679 | |
680 /* | |
681 * Open the IP provider. | |
682 */ | |
683 if ((fd = open(DEVARP, 0)) < 0) | |
684 syserr(DEVARP); | |
685 | |
686 /* | |
687 * Set the entry. | |
688 */ | |
689 (void) memcpy(LLADDR(&ar.xarp_ha), laddr, rdev->physaddrlen); | |
690 ar.xarp_ha.sdl_alen = rdev->physaddrlen; | |
691 ar.xarp_ha.sdl_family = AF_LINK; | |
692 (void) strioctl(fd, SIOCDXARP, -1, sizeof (struct xarpreq), | |
693 (char *)&ar); | |
694 if (strioctl(fd, SIOCSXARP, -1, sizeof (struct xarpreq), | |
695 (char *)&ar) < 0) | |
696 syserr("SIOCSXARP"); | |
697 | |
698 (void) close(fd); | |
699 } | |
700 | |
701 /* | |
702 * The RARP spec says we must be able to process ARP requests, | |
703 * even through the packet type is RARP. Let's hope this feature | |
704 * is not heavily used. | |
705 */ | |
706 static void | |
707 arp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost) | |
708 { | |
709 struct rarpreply *rrp; | |
710 struct ifdev *ifdev; | |
711 uchar_t *shap, *thap, *spap, *tpap; | |
712 int retval; | |
713 | |
714 shap = (uchar_t *)rp + sizeof (struct arphdr); | |
715 spap = shap + rp->ar_hln; | |
716 thap = spap + rp->ar_pln; | |
717 tpap = thap + rp->ar_hln; | |
718 | |
719 if (dflag) | |
720 debug("ARPOP_REQUEST"); | |
721 | |
722 for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) { | |
723 if (memcmp(&ifdev->ipaddr, tpap, sizeof (ipaddr_t)) == 0) | |
724 break; | |
725 } | |
726 if (ifdev == NULL) | |
727 return; | |
728 | |
729 rp->ar_op = ARPOP_REPLY; | |
730 (void) memcpy(shap, rdev->physaddr, rdev->physaddrlen); | |
731 (void) memcpy(spap, &ifdev->ipaddr, sizeof (ipaddr_t)); | |
732 (void) memcpy(thap, rdev->physaddr, rdev->physaddrlen); | |
733 | |
734 add_arp(rdev, tpap, thap); | |
735 | |
736 /* | |
737 * Create rarp reply structure. | |
738 */ | |
739 rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen + | |
740 rdev->ifrarplen); | |
741 if (rrp == NULL) | |
742 error("out of memory"); | |
743 rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply); | |
744 rrp->arprep = rrp->lldest + rdev->physaddrlen; | |
745 rrp->rdev = rdev; | |
746 | |
747 (void) memcpy(rrp->lldest, shost, rdev->physaddrlen); | |
748 (void) memcpy(rrp->arprep, rp, rdev->ifrarplen); | |
749 | |
750 retval = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen, | |
751 rrp->arprep, rdev->ifrarplen, NULL); | |
752 free(rrp); | |
753 if (retval != DLPI_SUCCESS) | |
754 error("dlpi_send failed: %s", dlpi_strerror(retval)); | |
755 } | |
756 | |
757 /* ARGSUSED */ | |
758 static void | |
759 do_delay_write(void *buf) | |
760 { | |
761 struct timeval tv; | |
762 struct rarpreply *rrp; | |
763 struct rarpdev *rdev; | |
764 int err; | |
765 | |
766 for (;;) { | |
767 if ((err = sema_wait(&delay_sema)) != 0) { | |
768 if (err == EINTR) | |
769 continue; | |
770 error("do_delay_write: sema_wait failed"); | |
771 } | |
772 | |
773 (void) mutex_lock(&delay_mutex); | |
774 rrp = delay_list; | |
775 rdev = rrp->rdev; | |
776 delay_list = delay_list->next; | |
777 (void) mutex_unlock(&delay_mutex); | |
778 | |
779 (void) gettimeofday(&tv, NULL); | |
780 if (tv.tv_sec < rrp->tv.tv_sec) | |
781 (void) sleep(rrp->tv.tv_sec - tv.tv_sec); | |
782 | |
783 err = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen, | |
784 rrp->arprep, rdev->ifrarplen, NULL); | |
785 if (err != DLPI_SUCCESS) | |
786 error("dlpi_send failed: %s", dlpi_strerror(err)); | |
787 | |
788 (void) free(rrp); | |
789 } | |
790 } | |
791 | |
792 /* ARGSUSED */ | |
793 static void | |
794 delay_write(struct rarpdev *rdev, struct rarpreply *rrp) | |
795 { | |
796 struct rarpreply *trp; | |
797 | |
798 (void) mutex_lock(&delay_mutex); | |
799 if (delay_list == NULL) { | |
800 delay_list = rrp; | |
801 } else { | |
802 trp = delay_list; | |
803 while (trp->next != NULL) | |
804 trp = trp->next; | |
805 trp->next = rrp; | |
806 } | |
807 (void) mutex_unlock(&delay_mutex); | |
808 | |
809 (void) sema_post(&delay_sema); | |
810 } | |
811 | |
812 /* | |
813 * See if we have a TFTP boot file for this guy. Filenames in TFTP | |
814 * boot requests are of the form <ipaddr> for Sun-3's and of the form | |
815 * <ipaddr>.<arch> for all other architectures. Since we don't know | |
816 * the client's architecture, either format will do. | |
817 */ | |
818 static int | |
819 mightboot(ipaddr_t ipa) | |
820 { | |
821 char path[MAXPATHL]; | |
822 DIR *dirp; | |
823 struct dirent *dp; | |
824 | |
825 (void) snprintf(path, sizeof (path), "%s/%08X", BOOTDIR, ipa); | |
826 | |
827 /* | |
828 * Try a quick access() first. | |
829 */ | |
830 if (access(path, 0) == 0) | |
831 return (1); | |
832 | |
833 /* | |
834 * Not there, do it the slow way by | |
835 * reading through the directory. | |
836 */ | |
837 (void) sprintf(path, "%08X", ipa); | |
838 | |
839 if (!(dirp = opendir(BOOTDIR))) | |
840 return (0); | |
841 | |
842 while ((dp = readdir(dirp)) != NULL) { | |
843 if (strncmp(dp->d_name, path, 8) != 0) | |
844 continue; | |
845 if ((strlen(dp->d_name) != 8) && (dp->d_name[8] != '.')) | |
846 continue; | |
847 break; | |
848 } | |
849 | |
850 (void) closedir(dirp); | |
851 | |
852 return ((dp != NULL) ? 1 : 0); | |
853 } | |
854 | |
855 /* | |
856 * Get our IP address and local netmask. | |
857 */ | |
858 static void | |
859 get_ifdata(char *dev, int unit, ipaddr_t *ipp, ipaddr_t *maskp) | |
860 { | |
861 int fd; | |
862 struct ifreq ifr; | |
863 struct sockaddr_in *sin; | |
864 | |
865 /* LINTED pointer */ | |
866 sin = (struct sockaddr_in *)&ifr.ifr_addr; | |
867 | |
868 /* | |
869 * Open the IP provider. | |
870 */ | |
871 if ((fd = open(DEVIP, 0)) < 0) | |
872 syserr(DEVIP); | |
873 | |
874 /* | |
875 * Ask IP for our IP address. | |
876 */ | |
877 (void) snprintf(ifr.ifr_name, sizeof (ifr.ifr_name), "%s%d", dev, unit); | |
878 if (strioctl(fd, SIOCGIFADDR, -1, sizeof (struct ifreq), | |
879 (char *)&ifr) < 0) | |
880 syserr("SIOCGIFADDR"); | |
881 *ipp = (ipaddr_t)ntohl(sin->sin_addr.s_addr); | |
882 | |
883 if (dflag) | |
884 debug("device %s%d address %s", dev, unit, | |
885 inet_ntoa(sin->sin_addr)); | |
886 | |
887 /* | |
888 * Ask IP for our netmask. | |
889 */ | |
890 if (strioctl(fd, SIOCGIFNETMASK, -1, sizeof (struct ifreq), | |
891 (char *)&ifr) < 0) | |
892 syserr("SIOCGIFNETMASK"); | |
893 *maskp = (ipaddr_t)ntohl(sin->sin_addr.s_addr); | |
894 | |
895 if (dflag) | |
896 debug("device %s%d subnet mask %s", dev, unit, | |
897 inet_ntoa(sin->sin_addr)); | |
898 | |
899 /* | |
900 * Thankyou ip. | |
901 */ | |
902 (void) close(fd); | |
903 } | |
904 | |
905 /* | |
906 * Translate mac address to IP address. | |
907 * Return 0 on success, nonzero on failure. | |
908 */ | |
909 static int | |
910 get_ipaddr(struct rarpdev *rdev, uchar_t *laddr, uchar_t *ipp, ipaddr_t *ipaddr) | |
911 { | |
912 char host[MAXHOSTL]; | |
913 char hbuffer[BUFSIZE]; | |
914 struct hostent *hp, res; | |
915 int herror; | |
916 struct in_addr addr; | |
917 char **p; | |
918 struct ifdev *ifdev; | |
919 | |
920 if (rdev->physaddrlen != ETHERADDRL) { | |
921 if (dflag) | |
922 debug("%s %s", " cannot map non 6 byte hardware ", | |
923 "address to IP address"); | |
924 return (1); | |
925 } | |
926 | |
927 /* | |
928 * Translate mac address to hostname and IP address. | |
929 */ | |
930 if (ether_ntohost(host, (struct ether_addr *)laddr) != 0 || | |
931 !(hp = gethostbyname_r(host, &res, hbuffer, sizeof (hbuffer), | |
932 &herror)) || | |
933 hp->h_addrtype != AF_INET || hp->h_length != sizeof (ipaddr_t)) { | |
934 if (dflag) | |
935 debug("could not map hardware address to IP address"); | |
936 return (1); | |
937 } | |
938 | |
939 /* | |
940 * Find the IP address on the right net. | |
941 */ | |
942 for (p = hp->h_addr_list; *p; p++) { | |
943 (void) memcpy(&addr, *p, sizeof (ipaddr_t)); | |
944 for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) { | |
945 if (dflag) { | |
946 struct in_addr daddr; | |
947 ipaddr_t netnum; | |
948 | |
949 netnum = htonl(ifdev->if_netnum); | |
950 (void) memcpy(&daddr, &netnum, | |
951 sizeof (ipaddr_t)); | |
952 if (ifdev->lunit == -1) | |
953 debug("trying physical netnum %s" | |
954 " mask %x", inet_ntoa(daddr), | |
955 ifdev->if_netmask); | |
956 else | |
957 debug("trying logical %d netnum %s" | |
958 " mask %x", ifdev->lunit, | |
959 inet_ntoa(daddr), | |
960 ifdev->if_netmask); | |
961 } | |
962 if ((ntohl(addr.s_addr) & ifdev->if_netmask) == | |
963 ifdev->if_netnum) { | |
964 /* | |
965 * Return the correct IP address. | |
966 */ | |
967 (void) memcpy(ipp, &addr, sizeof (ipaddr_t)); | |
968 | |
969 /* | |
970 * Return the interface's ipaddr | |
971 */ | |
972 (void) memcpy(ipaddr, &ifdev->ipaddr, | |
973 sizeof (ipaddr_t)); | |
974 | |
975 return (0); | |
976 } | |
977 } | |
978 } | |
979 | |
980 if (dflag) | |
981 debug("got host entry but no IP address on this net"); | |
982 return (1); | |
983 } | |
984 | |
985 static int | |
986 strioctl(int fd, int cmd, int timout, int len, char *dp) | |
987 { | |
988 struct strioctl si; | |
989 | |
990 si.ic_cmd = cmd; | |
991 si.ic_timout = timout; | |
992 si.ic_len = len; | |
993 si.ic_dp = dp; | |
994 return (ioctl(fd, I_STR, &si)); | |
995 } | |
996 | |
997 static void | |
998 usage(void) | |
999 { | |
1000 error("Usage: %s [ -ad ] device unit", cmdname); | |
1001 } | |
1002 | |
1003 static void | |
1004 syserr(const char *s) | |
1005 { | |
1006 char buf[256]; | |
1007 int status = 1; | |
1008 | |
1009 (void) snprintf(buf, sizeof (buf), "%s: %s", s, strerror(errno)); | |
1010 (void) fprintf(stderr, "%s: %s\n", cmdname, buf); | |
1011 syslog(LOG_ERR, "%s", buf); | |
1012 thr_exit(&status); | |
1013 } | |
1014 | |
1015 static void | |
1016 error(const char *fmt, ...) | |
1017 { | |
1018 char buf[256]; | |
1019 va_list ap; | |
1020 int status = 1; | |
1021 | |
1022 va_start(ap, fmt); | |
1023 (void) vsprintf(buf, fmt, ap); | |
1024 va_end(ap); | |
1025 (void) fprintf(stderr, "%s: %s\n", cmdname, buf); | |
1026 syslog(LOG_ERR, buf); | |
1027 thr_exit(&status); | |
1028 } | |
1029 | |
1030 /*PRINTFLIKE1*/ | |
1031 static void | |
1032 debug(char *fmt, ...) | |
1033 { | |
1034 va_list ap; | |
1035 | |
1036 (void) mutex_lock(&debug_mutex); | |
1037 va_start(ap, fmt); | |
1038 (void) fprintf(stderr, "%s:[%u] ", cmdname, thr_self()); | |
1039 (void) vfprintf(stderr, fmt, ap); | |
1040 (void) fprintf(stderr, "\n"); | |
1041 va_end(ap); | |
1042 (void) mutex_unlock(&debug_mutex); | |
1043 } |