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 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <assert.h>
36 #include <string.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <net/if.h>
40 #include <net/if_arp.h>
41 #include <netinet/in_systm.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netinet/if_ether.h>
45 #include <netinet/ip.h>
46 #include <netinet/udp.h>
47 #include <stropts.h>
48 #include <stdio.h>
49 #include <ctype.h>
50 #include <syslog.h>
51 #include <netinet/dhcp.h>
52 #include <dhcp_symbol.h>
53 #include "dhcpd.h"
54 #include "per_dnet.h"
55 #include "interfaces.h"
56 #include <v4_sum_impl.h>
57 #include <locale.h>
58
59 static int socksize = 64 * 1024; /* large socket window size for data */
60 static const uchar_t magic_cookie[] = BOOTMAGIC;
61 static void disp_if(IF *);
62
63 /*
64 * Network interface configuration. This file contains routines which
65 * handle the input side of the DHCP/BOOTP/Relay agent. Multiple interfaces
66 * are handled by identifying explicitly each interface, and creating a
67 * stream for each. If only one usable interface exists, then a "normal"
68 * UDP socket is used for simplicity's sake.
69 */
70
71 IF *if_head; /* head of interfaces list */
72 mutex_t if_head_mtx; /* mutex for adding/deleting IF list entries */
73 char *interfaces; /* user specified interfaces */
74 static int num_interfaces; /* # of usable interfaces on the system */
75
76 static char *
77 dsrvr_socktype(dsrvr_socktype_t stype)
78 {
79 char *rp;
80
81 switch (stype) {
82 case DSRVR_LBCAST:
83 rp = "limited broadcast";
84 break;
85 case DSRVR_DBCAST:
86 rp = "directed broadcast";
87 break;
88 case DSRVR_UCAST:
89 rp = "unicast";
90 break;
91 }
92 return (rp);
93 }
94
95 /*
96 * Given two packets, match them based on BOOTP header operation, packet len,
97 * hardware type, flags, ciaddr, DHCP type, client id, or chaddr.
98 * Returns B_TRUE if they match, B_FALSE otherwise.
99 */
100 static boolean_t
101 match_plp(PKT_LIST *alp, PKT_LIST *blp)
102 {
103 DHCP_OPT *a, *b;
104
105 assert(alp != NULL && blp != NULL);
106
107 if (alp->pkt->op != blp->pkt->op ||
108 alp->len != alp->len ||
109 alp->pkt->htype != blp->pkt->htype ||
110 alp->pkt->flags != blp->pkt->flags ||
111 alp->pkt->ciaddr.s_addr != blp->pkt->ciaddr.s_addr)
112 return (B_FALSE); /* not even the same BOOTP type. */
113
114 #ifdef DEBUG
115 if (alp->pkt->giaddr.s_addr != blp->pkt->giaddr.s_addr) {
116 dhcpmsg(LOG_DEBUG,
117 "%04d match_plp: giaddr mismatch on 0x%x, 0x%x\n",
118 thr_self());
119 }
120 #endif /* DEBUG */
121
122 a = alp->opts[CD_DHCP_TYPE];
123 b = blp->opts[CD_DHCP_TYPE];
124 if (a == NULL && b == NULL) {
125 /* bootp */
126 if (memcmp(alp->pkt->chaddr, blp->pkt->chaddr,
127 alp->pkt->hlen) == 0)
128 return (B_TRUE);
129 } else if (a != NULL && b != NULL) {
130 if (a->value[0] == b->value[0]) {
131 /* dhcp - packet types match. */
132 a = alp->opts[CD_CLIENT_ID];
133 b = blp->opts[CD_CLIENT_ID];
134 if (a != NULL && b != NULL) {
135 if (memcmp(a->value, b->value, a->len) == 0)
136 return (B_TRUE);
137 } else {
138 if (memcmp(alp->pkt->chaddr, blp->pkt->chaddr,
139 alp->pkt->hlen) == 0)
140 return (B_TRUE);
141 }
142 }
143 }
144 return (B_FALSE);
145 }
146
147 /*
148 * Given a packet, searches for a later packet in the
149 * interface's client list. If the search is successful, the argument
150 * packet is deleted, and the later packet is returned with the appropriate
151 * fields/options modified.
152 *
153 * Matches are based on match_plp(). The list is scanned until the final packet
154 * which "matches" is found. The last match replaces
155 * the argument plp. Duplicates are deleted.
156 *
157 * General Notes: After the first candidate is found, the list is checked to
158 * the tail of the list for other matches. For each packet which is deleted.
159 * the duplicate statistic is incremented for each one. If no candidate is
160 * found, then the argument plp is returned.
161 *
162 * Caveats: What about length and contents of packets? By definition, a
163 * client is not supposed to be altering this between frames, so we should
164 * be ok. Since the argument plp may be destroyed, it is assumed to be
165 * detached.
166 */
167 PKT_LIST *
168 refresh_pktlist(dsvc_clnt_t *pcd, PKT_LIST *plp)
169 {
170 PKT_LIST *wplp, *tplp, *retplp = NULL;
171 IF *ifp = pcd->ifp;
172
173 assert(MUTEX_HELD(&pcd->pkt_mtx));
174
175 wplp = pcd->pkthead;
176 while (wplp != NULL) {
177 if (match_plp(plp, wplp)) {
178 pcd->pending--;
179
180 (void) mutex_lock(&ifp->ifp_mtx);
181 ifp->duplicate++;
182 (void) mutex_unlock(&ifp->ifp_mtx);
183
184 /*
185 * Note that tplp, retplp can be synonyms for
186 * wplp. The synonyms are used because moldy plp's
187 * will be nuked, and the plp to return will be
188 * detached.
189 */
190 tplp = wplp;
191 wplp = wplp->next;
192
193 if (retplp != NULL) {
194 /* moldy duplicates */
195 free_plp(retplp);
196 }
197 retplp = tplp;
198 detach_plp(pcd, retplp);
199 } else {
200 wplp = wplp->next;
201 }
202 }
203
204 if (retplp == NULL)
205 retplp = plp;
206 else {
207 if (debug) {
208 dhcpmsg(LOG_DEBUG,
209 "%04d: Refreshed (0x%p) to (0x%p)\n",
210 thr_self(), (void *)plp, (void *)retplp);
211 }
212 free_plp(plp);
213 }
214
215 return (retplp);
216 }
217
218 /*
219 * Queries the IP transport layer for configured interfaces. Those that
220 * are acceptable for use by our daemon have these characteristics:
221 *
222 * Not loopback
223 * Is UP
224 *
225 * Sets num_interfaces global to number of valid, selected interfaces.
226 *
227 * Returns: 0 for success, the appropriate errno on fatal failure.
228 *
229 * Notes: Code gleaned from the in.rarpd, solaris 2.2.
230 */
231 static int
232 find_interfaces(void)
233 {
234 int i, k, ip, reqsize, numifs;
235 boolean_t found;
236 ushort_t mtu_tmp;
237 struct ifreq *reqbuf, *ifr;
238 struct ifconf ifconf;
239 IF *ifp, *if_tail;
240 struct sockaddr_in *sin;
241 char **user_if;
242 ENCODE *hecp;
243
244 if ((ip = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
245 dhcpmsg(LOG_ERR, "Error opening socket: %s\n",
246 strerror(errno));
247 return (1);
248 }
249
250 if (ioctl(ip, SIOCGIFNUM, &numifs) < 0) {
251 dhcpmsg(LOG_WARNING,
252 "Error discovering number of network interfaces: %s\n",
253 strerror(errno));
254 (void) close(ip);
255 return (1);
256 }
257
258 reqsize = numifs * sizeof (struct ifreq);
259 reqbuf = (struct ifreq *)smalloc(reqsize);
260
261 ifconf.ifc_len = reqsize;
262 ifconf.ifc_buf = (caddr_t)reqbuf;
263
264 if (ioctl(ip, SIOCGIFCONF, &ifconf) < 0) {
265 dhcpmsg(LOG_ERR,
266 "Error getting network interface information: %s\n",
267 strerror(errno));
268 free(reqbuf);
269 (void) close(ip);
270 return (1);
271 }
272
273 /*
274 * Verify that user specified interfaces are valid.
275 */
276 user_if = (char **)smalloc(numifs * sizeof (char *));
277 if (interfaces != NULL) {
278 for (i = 0; i < numifs; i++) {
279 user_if[i] = strtok(interfaces, ",");
280 if (user_if[i] == NULL)
281 break; /* we're done */
282 interfaces = NULL; /* for next call to strtok() */
283
284 for (found = B_FALSE, ifr = ifconf.ifc_req;
285 ifr < &ifconf.ifc_req[ifconf.ifc_len /
286 sizeof (struct ifreq)]; ifr++) {
287 if (strcmp(user_if[i], ifr->ifr_name) == 0) {
288 found = B_TRUE;
289 break;
290 }
291 }
292 if (!found) {
293 dhcpmsg(LOG_ERR,
294 "Invalid network interface: %s\n",
295 user_if[i]);
296 free(reqbuf);
297 free(user_if);
298 (void) close(ip);
299 return (1);
300 }
301 }
302 if (i < numifs)
303 user_if[i] = NULL;
304 } else
305 user_if[0] = NULL;
306
307 /*
308 * For each interface, build an interface structure. Ignore any
309 * LOOPBACK or down interfaces.
310 */
311 if_tail = if_head = NULL;
312 for (ifr = ifconf.ifc_req;
313 ifr < &ifconf.ifc_req[ifconf.ifc_len / sizeof (struct ifreq)];
314 ifr++) {
315 if (ioctl(ip, SIOCGIFFLAGS, ifr) < 0) {
316 dhcpmsg(LOG_ERR,
317 "Error encountered getting interface: %s flags: %s\n",
318 ifr->ifr_name, strerror(errno));
319 continue;
320 }
321 if ((ifr->ifr_flags & IFF_LOOPBACK) ||
322 !(ifr->ifr_flags & IFF_UP))
323 continue;
324
325 num_interfaces++; /* all possible interfaces counted */
326
327 /*
328 * If the user specified a list of interfaces,
329 * we'll only consider the ones specified.
330 */
331 if (user_if[0] != NULL) {
332 for (i = 0; i < numifs; i++) {
333 if (user_if[i] == NULL)
334 break; /* skip this interface */
335 if (strcmp(user_if[i], ifr->ifr_name) == 0)
336 break; /* user wants this one */
337 }
338 if (i == numifs || user_if[i] == NULL)
339 continue; /* skip this interface */
340 } else if (strchr(ifr->ifr_name, ':') != NULL)
341 continue; /* skip virtual interfaces */
342
343 ifp = (IF *)smalloc(sizeof (IF));
344 (void) strcpy(ifp->nm, ifr->ifr_name);
345
346 ifp->ifceno = if_nametoindex(ifp->nm);
347 ifp->flags = ifr->ifr_flags;
348 for (k = 0; k < DSRVR_NUM_DESC; k++)
349 ifp->descs[k] = -1;
350
351 /*
352 * Broadcast address. Not valid for POINTOPOINT
353 * connections.
354 */
355 if ((ifp->flags & IFF_POINTOPOINT) == 0) {
356 if (ifp->flags & IFF_BROADCAST) {
357 if (ioctl(ip, SIOCGIFBRDADDR, ifr) < 0) {
358 dhcpmsg(LOG_ERR, "Error encountered \
359 getting interface: %s broadcast address: %s\n", ifp->nm, strerror(errno));
360 free(ifp);
361 num_interfaces--;
362 continue;
363 }
364 /* LINTED [alignment ok] */
365 sin = (struct sockaddr_in *)&ifr->ifr_addr;
366 ifp->bcast = sin->sin_addr;
367 } else
368 ifp->bcast.s_addr = htonl(INADDR_ANY);
369
370 hecp = make_encode(DSYM_STANDARD, CD_BROADCASTADDR,
371 sizeof (struct in_addr), &ifp->bcast,
372 ENC_COPY);
373 replace_encode(&ifp->ecp, hecp, ENC_DONT_COPY);
374 }
375
376 /* Subnet mask */
377 if (ioctl(ip, SIOCGIFNETMASK, ifr) < 0) {
378 dhcpmsg(LOG_ERR, "Error encountered getting \
379 interface: %s netmask: %s\n", ifp->nm, strerror(errno));
380 free_encode_list(ifp->ecp);
381 free(ifp);
382 num_interfaces--;
383 continue;
384 }
385 /* LINTED [alignment ok] */
386 sin = (struct sockaddr_in *)&ifr->ifr_addr;
387 ifp->mask = sin->sin_addr;
388 hecp = make_encode(DSYM_STANDARD, CD_SUBNETMASK,
389 sizeof (struct in_addr), &ifp->mask, ENC_COPY);
390 replace_encode(&ifp->ecp, hecp, ENC_DONT_COPY);
391
392 /* Address */
393 if (ioctl(ip, SIOCGIFADDR, ifr) < 0) {
394 dhcpmsg(LOG_ERR, "Error encountered getting \
395 interface: %s address: %s\n", ifp->nm, strerror(errno));
396 free_encode_list(ifp->ecp);
397 free(ifp);
398 num_interfaces--;
399 continue;
400 }
401 /* LINTED [alignment ok] */
402 sin = (struct sockaddr_in *)&ifr->ifr_addr;
403 ifp->addr = sin->sin_addr;
404
405 /* MTU */
406 if (ioctl(ip, SIOCGIFMTU, ifr) < 0) {
407 dhcpmsg(LOG_ERR, "Error encountered getting \
408 interface: %s MTU: %s\n", ifp->nm, strerror(errno));
409 free_encode_list(ifp->ecp);
410 free(ifp);
411 num_interfaces--;
412 continue;
413 }
414
415 ifp->mtu = ifr->ifr_metric;
416 mtu_tmp = htons(ifp->mtu);
417 hecp = make_encode(DSYM_STANDARD, CD_MTU, 2,
418 &mtu_tmp, ENC_COPY);
419 replace_encode(&ifp->ecp, hecp, ENC_DONT_COPY);
420
421 /* Attach to interface list */
422 if (!if_tail) {
423 (void) mutex_init(&if_head_mtx, USYNC_THREAD, 0);
424 (void) mutex_lock(&if_head_mtx);
425 if_tail = if_head = ifp;
426 (void) mutex_unlock(&if_head_mtx);
427 } else {
428 (void) mutex_lock(&if_head_mtx);
429 if_tail->next = ifp;
430 if_tail = ifp;
431 (void) mutex_unlock(&if_head_mtx);
432 }
433 }
434
435 free(reqbuf);
436 free(user_if);
437 (void) close(ip);
438
439 if (if_head == NULL) {
440 num_interfaces = 0;
441 dhcpmsg(LOG_ERR, "Cannot find any valid interfaces.\n");
442 (void) mutex_destroy(&if_head_mtx);
443 return (EINVAL);
444 }
445 return (0);
446 }
447
448 /*
449 * Destroy an *uninitialized* IF structure - returns next ifp.
450 */
451 static IF *
452 zap_ifp(IF **ifp_prevpp, IF *ifp)
453 {
454 IF *tifp;
455
456 assert(MUTEX_HELD(&if_head_mtx));
457
458 if (*ifp_prevpp == ifp) {
459 if_head = ifp->next;
460 *ifp_prevpp = if_head;
461 } else
462 (*ifp_prevpp)->next = ifp->next;
463
464 tifp = ifp->next;
465
466 free(ifp);
467
468 return (tifp);
469 }
470
471 /*
472 * Monitor thread function. Poll on interface descriptors. Add valid BOOTP
473 * packets to interfaces PKT_LIST.
474 *
475 * Because the buffer will potentially contain the ip/udp headers, we flag
476 * this by setting the 'offset' field to the length of the two headers so that
477 * free_plp() can "do the right thing"
478 *
479 * Monitor the given interface. Signals are handled by sig_client thread.
480 *
481 * We make some attempt to deal with marginal interfaces as follows. We
482 * keep track of system errors (errors) and protocol errors (ifp->errors).
483 * If we encounter more than DHCP_MON_SYSERRS in DHCP_MON_ERRINTVL,
484 * then the interface thread will put itself to sleep for DHCP_MON_SLEEP
485 * minutes.
486 *
487 * MT SAFE
488 */
489 static void *
490 monitor_interface(void *argp)
491 {
492 PKT_LIST *plp, *tplp;
493 IF *ifp = (IF *)argp;
494 int errors, err, i;
495 uint_t verify_len;
496 struct pollfd pfd[DSRVR_NUM_DESC];
497 struct strbuf data;
498 char cbuf[DN_MAX_CID_LEN], ntoab[INET_ADDRSTRLEN];
499 time_t err_interval;
500 dn_rec_t dn;
501 dsvc_dnet_t *pnd;
502 dsvc_clnt_t *pcd;
503 struct in_addr netaddr, subnetaddr;
504 dsvc_pendclnt_t *workp;
505 int open_ret;
506 dsvc_thr_t *freep;
507 thread_t tid;
508 boolean_t existing_allocation;
509
510 if (debug) {
511 dhcpmsg(LOG_DEBUG, "Monitor (%04d/%s) started...\n",
512 ifp->if_thread, ifp->nm);
513 }
514
515 if (verbose)
516 disp_if(ifp);
517
518 pfd[DSRVR_LBCAST].fd = ifp->descs[DSRVR_LBCAST];
519 pfd[DSRVR_LBCAST].events = POLLIN | POLLPRI;
520 pfd[DSRVR_DBCAST].fd = ifp->descs[DSRVR_DBCAST];
521 pfd[DSRVR_DBCAST].events = POLLIN | POLLPRI;
522 pfd[DSRVR_UCAST].fd = ifp->descs[DSRVR_UCAST];
523 pfd[DSRVR_UCAST].events = POLLIN | POLLPRI;
524
525 err_interval = time(NULL) + DHCP_MON_ERRINTVL;
526 errors = 0;
527 while (time_to_go == 0) {
528 if (errors > DHCP_MON_SYSERRS) {
529 if (time(NULL) < err_interval) {
530 dhcpmsg(LOG_WARNING,
531 "Monitor (%04d/%s): Too many system errors (%d), pausing for %d minute(s)...\n",
532 ifp->if_thread, ifp->nm, errors,
533 DHCP_MON_SYSERRS);
534 (void) sleep(DHCP_MON_SLEEP);
535 err_interval = time(NULL) + DHCP_MON_ERRINTVL;
536 }
537 errors = 0;
538 }
539 pfd[DSRVR_LBCAST].revents = 0;
540 pfd[DSRVR_DBCAST].revents = 0;
541 pfd[DSRVR_UCAST].revents = 0;
542 if (poll(&pfd[0], (nfds_t)DSRVR_NUM_DESC, INFTIM) < 0) {
543 dhcpmsg(LOG_ERR,
544 "Monitor (%04d/%s) Polling error: (%s).\n",
545 ifp->if_thread, ifp->nm, strerror(errno));
546 errors++;
547 continue;
548 }
549 /*
550 * See if we are to exit. We can't be holding any locks...
551 */
552 (void) mutex_lock(&ifp->ifp_mtx);
553 if (ifp->thr_exit) {
554 if (debug) {
555 dhcpmsg(LOG_DEBUG,
556 "Monitor (%04d/%s): exiting.\n",
557 ifp->if_thread, ifp->nm);
558 }
559 (void) mutex_unlock(&ifp->ifp_mtx);
560 break;
561 }
562 (void) mutex_unlock(&ifp->ifp_mtx);
563
564 /* examine each socket for packets in turn */
565 for (i = 0; i < DSRVR_NUM_DESC; i++) {
566 if (pfd[i].revents == 0)
567 continue;
568 if (pfd[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
569 dhcpmsg(LOG_ERR, "Network interface "
570 "error on device: %s(%s)\n", ifp->nm,
571 dsrvr_socktype(i));
572 errors++;
573 continue;
574 }
575 if (!(pfd[i].revents & (POLLIN | POLLRDNORM))) {
576 dhcpmsg(LOG_INFO, "Unsupported event "
577 "on device %s(%s): %d\n", ifp->nm,
578 dsrvr_socktype(i),
579 pfd[i].revents);
580 errors++;
581 continue;
582 }
583 data.buf = smalloc(ifp->mtu);
584 data.len = recv(ifp->descs[i], data.buf, ifp->mtu, 0);
585 if (data.len < 0) {
586 dhcpmsg(LOG_ERR, "Error: %s receiving UDP "
587 "datagrams on %s(%s)\n",
588 strerror(errno), ifp->nm,
589 dsrvr_socktype(i));
590 free(data.buf);
591 errors++;
592 continue;
593 } else
594 verify_len = data.len;
595
596 if (debug) {
597 dhcpmsg(LOG_INFO,
598 "Datagram received on network device: "
599 "%s(%s)\n", ifp->nm, dsrvr_socktype(i));
600 }
601
602 (void) mutex_lock(&ifp->ifp_mtx);
603 ifp->received++;
604 (void) mutex_unlock(&ifp->ifp_mtx);
605
606 if (verify_len < BASE_PKT_SIZE) {
607 if (verbose) {
608 dhcpmsg(LOG_INFO, "Short packet %d < "
609 "%d on %s(%s) ignored\n",
610 verify_len, sizeof (PKT),
611 ifp->nm, dsrvr_socktype(i));
612 }
613 free(data.buf);
614 (void) mutex_lock(&ifp->ifp_mtx);
615 ifp->errors++;
616 (void) mutex_unlock(&ifp->ifp_mtx);
617 continue;
618 }
619
620 plp = (PKT_LIST *)smalloc(sizeof (PKT_LIST));
621 plp->offset = 0;
622 plp->len = data.len;
623 /* LINTED [alignment ok] */
624 plp->pkt = (PKT *)data.buf;
625
626 if (plp->pkt->hops >= max_hops + 1) {
627 if (verbose) {
628 dhcpmsg(LOG_INFO, "%s(%s): Packet "
629 "dropped: too many hops: %d\n",
630 ifp->nm, dsrvr_socktype(i),
631 plp->pkt->hops);
632 }
633 free_plp(plp);
634 (void) mutex_lock(&ifp->ifp_mtx);
635 ifp->errors++;
636 (void) mutex_unlock(&ifp->ifp_mtx);
637 continue;
638 }
639
640 /* validate hardware len */
641 if (plp->pkt->hlen > sizeof (plp->pkt->chaddr))
642 plp->pkt->hlen = sizeof (plp->pkt->chaddr);
643
644 if (debug && plp->pkt->giaddr.s_addr != 0L &&
645 plp->pkt->giaddr.s_addr != ifp->addr.s_addr) {
646 dhcpmsg(LOG_INFO, "%s(%s): Packet received "
647 "from relay agent: %s\n", ifp->nm,
648 dsrvr_socktype(i), inet_ntop(AF_INET,
649 &plp->pkt->giaddr, ntoab, sizeof (ntoab)));
650 }
651
652 if (!server_mode) {
653 /*
654 * Relay agent mode. No further processing
655 * required ; we'll handle it here.
656 */
657 (void) mutex_lock(&if_head_mtx);
658 err = relay_agent(ifp, plp);
659 (void) mutex_unlock(&if_head_mtx);
660 if (err != 0) {
661 dhcpmsg(LOG_ERR, "Relay agent mode "
662 "failed: %d (%s) on: %s(%s)\n",
663 err, (plp->pkt->op == BOOTREPLY) ?
664 "reply" : "request", ifp->nm,
665 dsrvr_socktype(i));
666 errors++; /* considered system error */
667 } else {
668 /* update statistics */
669 (void) mutex_lock(&ifp->ifp_mtx);
670 ifp->processed++;
671 ifp->received++;
672 (void) mutex_unlock(&ifp->ifp_mtx);
673 }
674 free_plp(plp);
675 continue;
676 }
677
678 /* ============ Packets destined for bootp and dhcp server modules ========== */
679
680 /*
681 * Allow packets without RFC1048 magic cookies.
682 * Just don't do an options scan on them,
683 * thus we treat them as plain BOOTP packets.
684 * The BOOTP server can deal with requests of
685 * this type.
686 */
687 if (memcmp(plp->pkt->cookie, magic_cookie,
688 sizeof (magic_cookie)) != 0) {
689 if (verbose) {
690 dhcpmsg(LOG_INFO, "%s(%s): Client: %s "
691 "using non-RFC1048 BOOTP cookie.\n",
692 ifp->nm, dsrvr_socktype(i),
693 disp_cid(plp, cbuf, sizeof (cbuf)));
694 }
695 plp->rfc1048 = B_FALSE;
696 } else {
697 /*
698 * Scan the options in the packet and fill in
699 * the opts and vs fields in the * clientlist
700 * structure. If there's a DHCP message type
701 * in the packet then it's a DHCP packet;
702 * otherwise it's a BOOTP packet. Standard
703 * options are RFC1048 style.
704 */
705 if (dhcp_options_scan(plp, B_FALSE) != 0) {
706 dhcpmsg(LOG_ERR, "Garbled DHCP/BOOTP "
707 "packet received on: %s(%s)\n",
708 ifp->nm, dsrvr_socktype(i));
709 free_plp(plp);
710 (void) mutex_lock(&ifp->ifp_mtx);
711 ifp->errors++;
712 (void) mutex_unlock(&ifp->ifp_mtx);
713 continue;
714 }
715 plp->rfc1048 = B_TRUE;
716 }
717
718 /*
719 * Link the new packet to the list of packets
720 * for this network/client. No need to lock plp,
721 * since it isn't visible outside this function yet.
722 */
723 if (plp->pkt->op != BOOTREQUEST) {
724 dhcpmsg(LOG_ERR, "Unexpected packet received "
725 "on %s(%s), BOOTP server port. Ignored.\n",
726 ifp->nm, dsrvr_socktype(i));
727 free_plp(plp);
728 (void) mutex_lock(&ifp->ifp_mtx);
729 ifp->errors++;
730 (void) mutex_unlock(&ifp->ifp_mtx);
731 continue;
732 }
733
734 determine_network(ifp, plp, &netaddr, &subnetaddr);
735 if ((err = open_dnet(&pnd, &netaddr, &subnetaddr)) !=
736 DSVC_SUCCESS) {
737 if (verbose && err == DSVC_NO_TABLE) {
738 netaddr.s_addr &= subnetaddr.s_addr;
739 dhcpmsg(LOG_INFO, "%s(%s): There is no "
740 "%s dhcp-network table for DHCP "
741 "client's network.\n", ifp->nm,
742 dsrvr_socktype(i),
743 inet_ntop(AF_INET, &netaddr,
744 ntoab, sizeof (ntoab)));
745 }
746 free_plp(plp);
747 continue;
748 }
749
750 /* Find client */
751 get_clnt_id(plp, (uchar_t *)dn.dn_cid,
752 sizeof (dn.dn_cid), &dn.dn_cid_len);
753 open_ret = open_clnt(pnd, &pcd, dn.dn_cid,
754 dn.dn_cid_len, B_FALSE);
755
756 if (pcd == NULL) {
757 free_plp(plp);
758 close_dnet(pnd, B_FALSE);
759 continue;
760 }
761
762 /*
763 * DOS via Packet flooding: ensure that each client's
764 * PKT_LIST never exceeds DHCP_MON_THRESHOLD pkts in
765 * length. If it does, we prune it from the head of
766 * the list, dropping sequential packets. Note that
767 * since DHCP is a multi-transaction protocol, we would
768 * like to be sure not to discard a REQUEST for an OFFER
769 * we've extended.
770 *
771 * TODO: we are still vulnerable to flooding attacks
772 * where bogus client ids are presented. This can be
773 * manually controlled via the MAX_CLIENTS and
774 * MAX_THREADS config file knobs.
775 */
776 (void) mutex_lock(&pcd->pkt_mtx);
777 if (pcd->pending > DHCP_MON_THRESHOLD) {
778 if ((tplp = pcd->pkthead) != NULL) {
779 detach_plp(pcd, tplp);
780 free_plp(tplp);
781 pcd->pending--;
782 }
783 }
784
785 if (pcd->pkthead == NULL)
786 pcd->pkthead = plp;
787 else {
788 pcd->pkttail->next = plp;
789 plp->prev = pcd->pkttail;
790 }
791 pcd->pkttail = plp;
792 pcd->pending++;
793 (void) mutex_unlock(&pcd->pkt_mtx);
794
795 /*
796 * Manage worker threads and deferred thread work list.
797 */
798 (void) mutex_lock(&pcd->pcd_mtx);
799 pcd->ifp = ifp;
800 if (pcd->clnt_thread == NULL &&
801 (pcd->flags & DHCP_PCD_CLOSING) == 0) {
802 existing_allocation = B_FALSE;
803 (void) mutex_lock(&pnd->thr_mtx);
804 if ((freep = pnd->thrhead) != NULL) {
805 existing_allocation = B_TRUE;
806 /*
807 * Restart a suspended thread.
808 */
809 pnd->thrhead = freep->thr_next;
810 if (pnd->thrhead == NULL)
811 pnd->thrtail = NULL;
812 (void) mutex_unlock(&pnd->thr_mtx);
813
814 (void) mutex_lock(&freep->thr_mtx);
815 freep->thr_flags &= ~DHCP_THR_LIST;
816 freep->thr_next = NULL;
817 freep->thr_pcd = pcd;
818 (void) mutex_unlock(&freep->thr_mtx);
819 pcd->clnt_thread = freep;
820 } else if (max_threads != -1 &&
821 pnd->nthreads >= max_threads) {
822 /*
823 * Add client once to deferred work
824 * list, to keep track of future work.
825 */
826 if ((pcd->flags & DHCP_PCD_WORK) == 0) {
827 pcd->flags |= DHCP_PCD_WORK;
828 workp = (dsvc_pendclnt_t *)
829 smalloc(
830 sizeof (dsvc_pendclnt_t));
831 get_clnt_id(plp,
832 (uchar_t *)workp->pnd_cid,
833 sizeof (workp->pnd_cid),
834 &workp->pnd_cid_len);
835 if (pnd->workhead == NULL)
836 pnd->workhead = workp;
837 else {
838 pnd->worktail->
839 pnd_next = workp;
840 }
841 pnd->worktail = workp;
842 }
843 (void) mutex_unlock(&pnd->thr_mtx);
844 (void) mutex_unlock(&pcd->pcd_mtx);
845 if (open_ret == DSVC_SUCCESS)
846 close_clnt(pcd, B_FALSE);
847 close_dnet(pnd, B_FALSE);
848 continue;
849 }
850 if (pcd->clnt_thread == NULL) {
851 pnd->nthreads++;
852 (void) mutex_unlock(&pnd->thr_mtx);
853 freep = pcd->clnt_thread =
854 (dsvc_thr_t *)
855 smalloc(sizeof (dsvc_thr_t));
856 (void) mutex_init(&freep->thr_mtx,
857 USYNC_THREAD, 0);
858 freep->thr_pcd = pcd;
859
860 /* Fire up a client thread. */
861 if (thr_create(NULL, 0, monitor_client,
862 freep, THR_BOUND | THR_SUSPENDED |
863 THR_DETACHED, &freep->thr_tid) !=
864 0) {
865 dhcpmsg(LOG_ERR, "%s(%s): "
866 "Error %s starting client "
867 "monitor thread.\n",
868 ifp->nm, dsrvr_socktype(i),
869 strerror(errno));
870 (void) mutex_lock(
871 &pnd->thr_mtx);
872 pnd->nthreads--;
873 (void) mutex_unlock(
874 &pnd->thr_mtx);
875 free(freep);
876 freep = pcd->clnt_thread = NULL;
877 }
878 }
879 if (freep != NULL) {
880 /*
881 * Continue the new or reused thread.
882 * Let it close the client.
883 */
884 open_ret = DSVC_BUSY;
885 tid = freep->thr_tid;
886 (void) mutex_unlock(&pcd->pcd_mtx);
887 pcd = NULL;
888 if (existing_allocation) {
889 (void) cond_signal(
890 &freep->thr_cv);
891 } else {
892 (void) thr_continue(tid);
893 }
894 }
895 }
896 if (pcd != NULL) {
897 (void) mutex_unlock(&pcd->pcd_mtx);
898 if (open_ret == DSVC_SUCCESS)
899 close_clnt(pcd, B_FALSE);
900 }
901 close_dnet(pnd, B_FALSE);
902 }
903 }
904 return (NULL);
905 }
906
907 /*
908 * close interface sockets
909 */
910 static void
911 close_sockets(IF *ifp) {
912 int i;
913
914 for (i = 0; i < DSRVR_NUM_DESC; i++) {
915 if (ifp->descs[i] == -1)
916 continue;
917 (void) close(ifp->descs[i]);
918 ifp->descs[i] = -1;
919 }
920 }
921
922 /*
923 * initialize interface sockets.
924 *
925 * Returns: 0 for success, -1 otherwise.
926 */
927 static int
928 init_sockets(IF *ifp)
929 {
930 int i, soptbuf = 1;
931 struct sockaddr_in sin;
932
933 sin.sin_family = AF_INET;
934 sin.sin_port = htons((short)IPPORT_BOOTPS + port_offset);
935
936 ifp->descs[DSRVR_LBCAST] = -1;
937 ifp->descs[DSRVR_DBCAST] = -1;
938 ifp->descs[DSRVR_UCAST] = -1;
939
940 for (i = 0; i < DSRVR_NUM_DESC; i++) {
941 ifp->descs[i] = socket(AF_INET, SOCK_DGRAM, 0);
942 if (ifp->descs[i] < 0) {
943 dhcpmsg(LOG_ERR, "Error opening socket on %s(%s) for "
944 "receiving UDP datagrams: %s\n",
945 ifp->nm, dsrvr_socktype(i), strerror(errno));
946 return (-1);
947 }
948
949 if (setsockopt(ifp->descs[i], SOL_SOCKET, SO_REUSEADDR,
950 &soptbuf, (int)sizeof (soptbuf)) < 0) {
951 dhcpmsg(LOG_DEBUG, "Setting socket option on %s(%s) "
952 "to allow reuse on send descriptor failed: %s\n",
953 ifp->nm, dsrvr_socktype(i), strerror(errno));
954 close_sockets(ifp);
955 return (-1);
956 }
957
958 (void) setsockopt(ifp->descs[i], SOL_SOCKET, SO_RCVBUF,
959 &socksize, sizeof (socksize));
960 (void) setsockopt(ifp->descs[i], SOL_SOCKET, SO_SNDBUF,
961 &socksize, sizeof (socksize));
962
963 switch (i) {
964 case DSRVR_LBCAST:
965 if (setsockopt(ifp->descs[i], IPPROTO_IP,
966 IP_BOUND_IF, &ifp->ifceno,
967 (int)sizeof (char *)) < 0) {
968 dhcpmsg(LOG_ERR,
969 "Bind to index failed on %s: %s\n",
970 ifp->nm, strerror(errno));
971 close_sockets(ifp);
972 return (-1);
973 }
974 sin.sin_addr.s_addr = htonl(INADDR_BROADCAST);
975 break;
976 case DSRVR_DBCAST:
977 sin.sin_addr.s_addr =
978 ifp->addr.s_addr & ifp->mask.s_addr;
979 break;
980 case DSRVR_UCAST:
981 /* We send out the unicast socket */
982 if (setsockopt(ifp->descs[i], SOL_SOCKET,
983 SO_BROADCAST, &soptbuf,
984 (int)sizeof (soptbuf)) < 0) {
985 dhcpmsg(LOG_ERR, "Setting socket "
986 "option on %s to allow broadcast "
987 "on send descriptor failed: %s\n",
988 ifp->nm, strerror(errno));
989 close_sockets(ifp);
990 return (-1);
991 }
992 sin.sin_addr.s_addr = ifp->addr.s_addr;
993 break;
994 }
995 if (bind(ifp->descs[i],
996 (struct sockaddr *)&sin, sizeof (sin)) < 0) {
997 dhcpmsg(LOG_ERR,
998 "Error binding to UDP socket on %s(%s): %s\n",
999 ifp->nm, dsrvr_socktype(i), strerror(errno));
1000 close_sockets(ifp);
1001 return (-1);
1002 }
1003 }
1004 return (0);
1005 }
1006
1007 /*
1008 * Based on the list generated by find_interfaces(), possibly modified by
1009 * user arguments, open a stream for each valid / requested interface.
1010 *
1011 * If:
1012 *
1013 * 1) Only one interface exists, open a standard bidirectional UDP
1014 * socket. Note that this is different than if only ONE
1015 * interface is requested (but more exist).
1016 *
1017 * 2) If more than one valid interface exists, then attach to the
1018 * datalink layer, push on the packet filter and buffering
1019 * modules, and wait for fragment 0 IP packets that contain
1020 * UDP packets with port 67 (server port).
1021 *
1022 * Comments:
1023 * Using DLPI to identify the interface thru which BOOTP
1024 * packets pass helps in providing the correct response.
1025 * Note that I will open a socket for use in transmitting
1026 * responses, suitably specifying the destination relay agent
1027 * or host. Note that if I'm unicasting to the client (broadcast
1028 * flag not set), that somehow I have to clue the IP layer about
1029 * the client's hw address. The only way I can see doing this is
1030 * making the appropriate ARP table entry.
1031 *
1032 * The only remaining unknown is dealing with clients that
1033 * require broadcasting, and multiple interfaces exist. I assume
1034 * that if I specify the interface's source address when
1035 * opening the socket, that a limited broadcast will be
1036 * directed to the correct net, and only the correct net.
1037 *
1038 * Returns: 0 for success, non-zero for failure.
1039 */
1040 int
1041 open_interfaces(void)
1042 {
1043 int inum, err = 0;
1044 IF *ifp, *ifp_prevp;
1045
1046 /* Uncover list of valid, user-selected interfaces to monitor */
1047 if ((err = find_interfaces()) != 0)
1048 return (err);
1049
1050 (void) mutex_lock(&if_head_mtx);
1051
1052 /*
1053 * Setup valid interfaces.
1054 */
1055 ifp = ifp_prevp = if_head;
1056 err = inum = 0;
1057 while (ifp != NULL) {
1058 if (init_sockets(ifp) < 0) {
1059 ifp = zap_ifp(&ifp_prevp, ifp);
1060 num_interfaces--;
1061 continue;
1062 }
1063
1064 /* Accounting */
1065 ifp->transmit = ifp->received = 0;
1066 ifp->duplicate = ifp->dropped = 0;
1067 ifp->processed = 0;
1068
1069 /* ifp structure lock */
1070 (void) mutex_init(&ifp->ifp_mtx, USYNC_THREAD, 0);
1071 ifp->thr_exit = 0;
1072
1073 /* fire up monitor thread */
1074 if (thr_create(NULL, 0, monitor_interface, ifp,
1075 THR_BOUND, &ifp->if_thread) != 0) {
1076 dhcpmsg(LOG_ERR,
1077 "Interface: %s - Error %s starting monitor thread.\n", ifp->nm,
1078 strerror(errno));
1079 close_sockets(ifp);
1080 (void) mutex_destroy(&ifp->ifp_mtx);
1081 ifp = zap_ifp(&ifp_prevp, ifp);
1082 num_interfaces--;
1083 continue;
1084 }
1085 inum++;
1086 ifp_prevp = ifp;
1087 ifp = ifp->next;
1088 }
1089 (void) mutex_unlock(&if_head_mtx);
1090
1091 /*
1092 * We must succeed in configuring at least one interface
1093 * to be considered successful.
1094 */
1095 if (num_interfaces == 0) {
1096 err = EINVAL;
1097 dhcpmsg(LOG_ERR, "Cannot configure any interfaces.\n");
1098 }
1099 return (err);
1100 }
1101
1102 /*
1103 * Detach the referenced plp from the client list.
1104 */
1105 void
1106 detach_plp(dsvc_clnt_t *pcd, PKT_LIST *plp)
1107 {
1108 assert(MUTEX_HELD(&pcd->pkt_mtx));
1109
1110 if (plp->prev == NULL) {
1111 pcd->pkthead = plp->next;
1112 if (pcd->pkthead != NULL)
1113 pcd->pkthead->prev = NULL;
1114 } else
1115 plp->prev->next = plp->next;
1116
1117 if (plp->next != NULL)
1118 plp->next->prev = plp->prev;
1119 else {
1120 pcd->pkttail = plp->prev;
1121 if (pcd->pkttail != NULL)
1122 pcd->pkttail->next = NULL;
1123 }
1124 plp->prev = plp->next = NULL;
1125 }
1126
1127 /*
1128 * Write a packet to an interface.
1129 *
1130 * Returns 0 on success otherwise non-zero.
1131 */
1132 int
1133 write_interface(IF *ifp, PKT *clientp, int len, struct sockaddr_in *to)
1134 {
1135 int err;
1136
1137 to->sin_family = AF_INET;
1138
1139 if ((err = sendto(ifp->descs[DSRVR_UCAST], clientp, len, 0,
1140 (struct sockaddr *)to, sizeof (struct sockaddr))) < 0) {
1141 dhcpmsg(LOG_ERR, "SENDTO: %s.\n", strerror(errno));
1142 return (err);
1143 }
1144
1145 (void) mutex_lock(&ifp->ifp_mtx);
1146 ifp->transmit++;
1147 (void) mutex_unlock(&ifp->ifp_mtx);
1148
1149 return (0);
1150 }
1151
1152 /*
1153 * Pop any packet filters, buffering modules, close stream, free encode
1154 * list, terminate monitor thread, free ifp. Return ifp next ptr.
1155 */
1156 static IF *
1157 close_interface(IF *ifp)
1158 {
1159 int err;
1160 IF *tifp;
1161
1162 assert(ifp != NULL);
1163
1164 assert(MUTEX_HELD(&if_head_mtx));
1165
1166 (void) mutex_lock(&ifp->ifp_mtx);
1167 ifp->thr_exit = 1;
1168
1169 close_sockets(ifp); /* thread will exit poll ... */
1170 (void) mutex_unlock(&ifp->ifp_mtx);
1171
1172 /*
1173 * Wait for the thread to exit. We release the if_head_mtx
1174 * lock, since the monitor thread(s) need to acquire it to traverse
1175 * the list - and we don't want to deadlock. Once the monitor thread
1176 * notices the thr_exit flag, it'll be gone anyway. Note that if_head
1177 * is changing (in close_interfaces()). At this point, only monitor
1178 * threads that haven't been reaped could be walking the interface
1179 * list. They will "see" the change in if_head.
1180 */
1181 (void) mutex_unlock(&if_head_mtx);
1182 if ((err = thr_join(ifp->if_thread, NULL, NULL)) != 0) {
1183 dhcpmsg(LOG_ERR,
1184 "Error %d while waiting for monitor %d of %s\n",
1185 err, ifp->if_thread, ifp->nm);
1186 }
1187 (void) mutex_lock(&if_head_mtx);
1188
1189 /*
1190 * Note: clients and their associated packet lists are freed prior
1191 * to interfaces being closed.
1192 */
1193
1194 /* free encode list */
1195 free_encode_list(ifp->ecp);
1196
1197 /* display statistics */
1198 disp_if_stats(ifp);
1199
1200 ifp->received = ifp->processed = 0;
1201
1202 (void) mutex_unlock(&ifp->ifp_mtx);
1203 (void) mutex_destroy(&ifp->ifp_mtx);
1204 tifp = ifp->next;
1205 free(ifp);
1206 return (tifp);
1207 }
1208
1209 /*
1210 * Close all interfaces, freeing up associated resources.
1211 * This should only be called from main() during final exit.
1212 */
1213 void
1214 close_interfaces(void)
1215 {
1216 (void) mutex_lock(&if_head_mtx);
1217 for (; if_head != NULL; if_head = close_interface(if_head)) {
1218 if (verbose) {
1219 dhcpmsg(LOG_INFO, "Closing interface: %s\n",
1220 if_head->nm);
1221 }
1222 }
1223 (void) mutex_unlock(&if_head_mtx);
1224 (void) mutex_destroy(&if_head_mtx);
1225 }
1226
1227 /*
1228 * display IF info. Must be MT Safe - called from monitor threads.
1229 */
1230 static void
1231 disp_if(IF *ifp)
1232 {
1233 char ntoab[INET_ADDRSTRLEN];
1234
1235 dhcpmsg(LOG_INFO, "Thread Id: %04d - Monitoring Interface: %s *****\n",
1236 ifp->if_thread, ifp->nm);
1237 dhcpmsg(LOG_INFO, "MTU: %d\tType: %s\n", ifp->mtu, "SOCKET");
1238 if ((ifp->flags & IFF_POINTOPOINT) == 0)
1239 dhcpmsg(LOG_INFO, "Broadcast: %s\n",
1240 inet_ntop(AF_INET, &ifp->bcast, ntoab, sizeof (ntoab)));
1241 dhcpmsg(LOG_INFO, "Netmask: %s\n",
1242 inet_ntop(AF_INET, &ifp->mask, ntoab, sizeof (ntoab)));
1243 dhcpmsg(LOG_INFO, "Address: %s\n",
1244 inet_ntop(AF_INET, &ifp->addr, ntoab, sizeof (ntoab)));
1245 }
1246
1247 /*
1248 * Display IF statistics.
1249 */
1250 void
1251 disp_if_stats(IF *ifp)
1252 {
1253 dhcpmsg(LOG_INFO, "Interface statistics for: %s **************\n",
1254 ifp->nm);
1255
1256 dhcpmsg(LOG_INFO, "Pending DHCP offers: %d\n", ifp->offers);
1257 dhcpmsg(LOG_INFO, "Total Packets Transmitted: %d\n", ifp->transmit);
1258 dhcpmsg(LOG_INFO, "Total Packets Received: %d\n", ifp->received);
1259 dhcpmsg(LOG_INFO, "Total Packet Duplicates: %d\n", ifp->duplicate);
1260 dhcpmsg(LOG_INFO, "Total Packets Dropped: %d\n", ifp->dropped);
1261 dhcpmsg(LOG_INFO, "Total Packets Processed: %d\n", ifp->processed);
1262 dhcpmsg(LOG_INFO, "Total Protocol Errors: %d\n", ifp->errors);
1263 }
1264
1265 /*
1266 * Setup the arp cache so that IP address 'ia' will be temporarily
1267 * bound to hardware address 'ha' of length 'len'. 'ia' is expected in
1268 * network order.
1269 *
1270 * Returns: 0 if the arp entry was made, 1 otherwise.
1271 */
1272 int
1273 set_arp(IF *ifp, struct in_addr *ia, uchar_t *ha, int len, uchar_t flags)
1274 {
1275 struct sockaddr_in *si;
1276 struct xarpreq arpreq;
1277 int err = 0;
1278 char scratch[DHCP_SCRATCH];
1279 uint_t scratch_len;
1280 char ntoab[INET_ADDRSTRLEN];
1281
1282 (void) memset((caddr_t)&arpreq, 0, sizeof (arpreq));
1283
1284 arpreq.xarp_ha.sdl_family = AF_LINK;
1285
1286 si = (struct sockaddr_in *)&arpreq.xarp_pa;
1287 si->sin_family = AF_INET;
1288 si->sin_addr = *ia; /* struct copy */
1289
1290 switch (flags) {
1291 case DHCP_ARP_ADD:
1292 if (debug) {
1293 scratch_len = sizeof (scratch);
1294 if (octet_to_hexascii(ha, len, scratch,
1295 &scratch_len) != 0) {
1296 dhcpmsg(LOG_DEBUG, "Cannot convert ARP \
1297 request to ASCII: %s: len: %d\n",
1298 inet_ntop(AF_INET, ia,
1299 ntoab, sizeof (ntoab)),
1300 len);
1301 } else {
1302 dhcpmsg(LOG_DEBUG,
1303 "Adding ARP entry: %s == %s\n",
1304 inet_ntop(AF_INET, ia,
1305 ntoab, sizeof (ntoab)),
1306 scratch);
1307 }
1308 }
1309 arpreq.xarp_flags = ATF_INUSE | ATF_COM;
1310 (void) memcpy(LLADDR(&arpreq.xarp_ha), ha, len);
1311 arpreq.xarp_ha.sdl_alen = len;
1312
1313 if (ioctl(ifp->descs[DSRVR_UCAST], SIOCSXARP, &arpreq) < 0) {
1314 dhcpmsg(LOG_ERR,
1315 "ADD: Cannot modify ARP table to add: %s\n",
1316 inet_ntop(AF_INET, ia, ntoab, sizeof (ntoab)));
1317 err = 1;
1318 }
1319 break;
1320 case DHCP_ARP_DEL:
1321 /* give it a good effort, but don't worry... */
1322 (void) ioctl(ifp->descs[DSRVR_UCAST], SIOCDXARP, &arpreq);
1323 break;
1324 default:
1325 err = 1;
1326 break;
1327 }
1328
1329 return (err);
1330 }
1331
1332 /*
1333 * Address and send a BOOTP reply packet appropriately. Does right thing
1334 * based on BROADCAST flag. Also checks if giaddr field is set, and
1335 * WE are the relay agent...
1336 *
1337 * Returns: 0 for success, nonzero otherwise (fatal)
1338 */
1339 int
1340 send_reply(IF *ifp, PKT *pp, int len, struct in_addr *dstp)
1341 {
1342 int local = B_FALSE;
1343 struct sockaddr_in to;
1344 struct in_addr if_in, cl_in;
1345 char ntoab[INET_ADDRSTRLEN];
1346
1347 if (pp->giaddr.s_addr != 0L && ifp->addr.s_addr !=
1348 pp->giaddr.s_addr) {
1349 /* Going thru a relay agent */
1350 to.sin_addr.s_addr = pp->giaddr.s_addr;
1351 to.sin_port = htons(IPPORT_BOOTPS + port_offset);
1352 } else {
1353 to.sin_port = htons(IPPORT_BOOTPC + port_offset);
1354
1355 if (ntohs(pp->flags) & BCAST_MASK) {
1356 /*
1357 * TODO - what should we do if broadcast
1358 * flag is set, but ptp connection?
1359 */
1360 if (debug)
1361 dhcpmsg(LOG_INFO,
1362 "Sending datagram to broadcast address.\n");
1363 to.sin_addr.s_addr = INADDR_BROADCAST;
1364 } else {
1365 /*
1366 * By default, we assume unicast!
1367 */
1368 to.sin_addr.s_addr = dstp->s_addr;
1369
1370 if (debug) {
1371 dhcpmsg(LOG_INFO,
1372 "Unicasting datagram to %s address.\n",
1373 inet_ntop(AF_INET, dstp,
1374 ntoab, sizeof (ntoab)));
1375 }
1376 if (ifp->addr.s_addr == pp->giaddr.s_addr) {
1377 /*
1378 * No doubt a reply packet which we, as
1379 * the relay agent, are supposed to deliver.
1380 * Local Delivery!
1381 */
1382 local = B_TRUE;
1383 } else {
1384 /*
1385 * We can't use the giaddr field to
1386 * determine whether the client is local
1387 * or remote. Use the client's address,
1388 * our interface's address, and our
1389 * interface's netmask to make this
1390 * determination.
1391 */
1392 if_in.s_addr = ntohl(ifp->addr.s_addr);
1393 if_in.s_addr &= ntohl(ifp->mask.s_addr);
1394 cl_in.s_addr = ntohl(dstp->s_addr);
1395 cl_in.s_addr &= ntohl(ifp->mask.s_addr);
1396 if (if_in.s_addr == cl_in.s_addr)
1397 local = B_TRUE;
1398 }
1399
1400 if (local) {
1401 /*
1402 * Local delivery. If we can make an
1403 * ARP entry we'll unicast. But only in
1404 * cases when we do have the chaddr handy.
1405 * RFC2855 and IPoIB are cases that do not
1406 * send chaddr and set hlen = 0. Identify
1407 * such media by their htype, and rely on
1408 * in-kernel ARP for them.
1409 */
1410 if ((ifp->flags & IFF_NOARP) == 0 &&
1411 ((pp->htype == ARPHRD_IB) ||
1412 (set_arp(ifp, dstp, pp->chaddr, pp->hlen,
1413 DHCP_ARP_ADD) == 0))) {
1414 to.sin_addr.s_addr = dstp->s_addr;
1415 } else {
1416 to.sin_addr.s_addr = INADDR_BROADCAST;
1417 }
1418 }
1419 }
1420 }
1421 return (write_interface(ifp, pp, len, &to));
1422 }
1423
1424 /*
1425 * Free pkts
1426 */
1427 void
1428 free_pktlist(dsvc_clnt_t *pcd)
1429 {
1430 PKT_LIST *plp, *plp_next;
1431 IF *ifp = pcd->ifp;
1432
1433 assert(MUTEX_HELD(&pcd->pcd_mtx));
1434
1435 plp = pcd->pkthead;
1436 while (plp != NULL) {
1437 plp_next = plp;
1438 plp = plp->next;
1439 free_plp(plp_next);
1440 ifp->dropped++;
1441 pcd->pending--;
1442 }
1443 pcd->pkthead = NULL;
1444 }
1445
1446 /* Check if address is one of the addresses we are listening on */
1447 boolean_t
1448 is_our_address(in_addr_t addr)
1449 {
1450 IF *ifp;
1451 boolean_t found = B_FALSE;
1452
1453 (void) mutex_lock(&if_head_mtx);
1454 for (ifp = if_head; ifp != NULL; ifp = ifp->next) {
1455 if (ifp->addr.s_addr == addr) {
1456 found = B_TRUE;
1457 break;
1458 }
1459 }
1460 (void) mutex_unlock(&if_head_mtx);
1461 return (found);
1462 }