xref: /netbsd-src/external/mpl/dhcp/dist/common/socket.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: socket.c,v 1.2 2018/04/07 22:37:29 christos Exp $	*/
2 
3 /* socket.c
4 
5    BSD socket interface code... */
6 
7 /*
8  * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1995-2003 by Internet Software Consortium
10  *
11  * This Source Code Form is subject to the terms of the Mozilla Public
12  * License, v. 2.0. If a copy of the MPL was not distributed with this
13  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  *   Internet Systems Consortium, Inc.
24  *   950 Charter Street
25  *   Redwood City, CA 94063
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: socket.c,v 1.2 2018/04/07 22:37:29 christos Exp $");
33 
34 /* SO_BINDTODEVICE support added by Elliot Poger (poger@leland.stanford.edu).
35  * This sockopt allows a socket to be bound to a particular interface,
36  * thus enabling the use of DHCPD on a multihomed host.
37  * If SO_BINDTODEVICE is defined in your system header files, the use of
38  * this sockopt will be automatically enabled.
39  * I have implemented it under Linux; other systems should be doable also.
40  */
41 
42 #include "dhcpd.h"
43 #include <isc/util.h>
44 #include <errno.h>
45 #include <sys/ioctl.h>
46 #include <sys/uio.h>
47 #include <sys/uio.h>
48 
49 #if defined(sun) && defined(USE_V4_PKTINFO)
50 #include <sys/sysmacros.h>
51 #include <net/if.h>
52 #include <sys/sockio.h>
53 #include <net/if_dl.h>
54 #include <sys/dlpi.h>
55 #endif
56 
57 #ifdef USE_SOCKET_FALLBACK
58 # if !defined (USE_SOCKET_SEND)
59 #  define if_register_send if_register_fallback
60 #  define send_packet send_fallback
61 #  define if_reinitialize_send if_reinitialize_fallback
62 # endif
63 #endif
64 
65 #if defined(DHCPv6)
66 /*
67  * XXX: this is gross.  we need to go back and overhaul the API for socket
68  * handling.
69  */
70 static int no_global_v6_socket = 0;
71 static unsigned int global_v6_socket_references = 0;
72 static int global_v6_socket = -1;
73 #if defined(RELAY_PORT)
74 static unsigned int relay_port_v6_socket_references = 0;
75 static int relay_port_v6_socket = -1;
76 #endif
77 
78 static void if_register_multicast(struct interface_info *info);
79 #endif
80 
81 /*
82  * We can use a single socket for AF_INET (similar to AF_INET6) on all
83  * interfaces configured for DHCP if the system has support for IP_PKTINFO
84  * and IP_RECVPKTINFO (for example Solaris 11).
85  */
86 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
87 static unsigned int global_v4_socket_references = 0;
88 static int global_v4_socket = -1;
89 #endif
90 
91 /*
92  * If we can't bind() to a specific interface, then we can only have
93  * a single socket. This variable insures that we don't try to listen
94  * on two sockets.
95  */
96 #if !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK)
97 static int once = 0;
98 #endif /* !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK) */
99 
100 /* Reinitializes the specified interface after an address change.   This
101    is not required for packet-filter APIs. */
102 
103 #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
104 void if_reinitialize_send (info)
105 	struct interface_info *info;
106 {
107 #if 0
108 #ifndef USE_SOCKET_RECEIVE
109 	once = 0;
110 	close (info -> wfdesc);
111 #endif
112 	if_register_send (info);
113 #endif
114 }
115 #endif
116 
117 #ifdef USE_SOCKET_RECEIVE
118 void if_reinitialize_receive (info)
119 	struct interface_info *info;
120 {
121 #if 0
122 	once = 0;
123 	close (info -> rfdesc);
124 	if_register_receive (info);
125 #endif
126 }
127 #endif
128 
129 #if defined (USE_SOCKET_SEND) || \
130 	defined (USE_SOCKET_RECEIVE) || \
131 		defined (USE_SOCKET_FALLBACK)
132 /* Generic interface registration routine... */
133 int
134 if_register_socket(struct interface_info *info, int family,
135 		   int *do_multicast, struct in6_addr *linklocal6)
136 {
137 	struct sockaddr_storage name;
138 	int name_len;
139 	int sock;
140 	int flag;
141 	int domain;
142 #ifdef DHCPv6
143 	struct sockaddr_in6 *addr6;
144 #endif
145 	struct sockaddr_in *addr;
146 
147 	/* INSIST((family == AF_INET) || (family == AF_INET6)); */
148 
149 #if !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK)
150 	/* Make sure only one interface is registered. */
151 	if (once) {
152 		log_fatal ("The standard socket API can only support %s",
153 		       "hosts with a single network interface.");
154 	}
155 	once = 1;
156 #endif
157 
158 	/*
159 	 * Set up the address we're going to bind to, depending on the
160 	 * address family.
161 	 */
162 	memset(&name, 0, sizeof(name));
163 	switch (family) {
164 #ifdef DHCPv6
165 	case AF_INET6:
166 		addr6 = (struct sockaddr_in6 *)&name;
167 		addr6->sin6_family = AF_INET6;
168 		addr6->sin6_port = local_port;
169 #if defined(RELAY_PORT)
170 		if (relay_port &&
171 		    ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM))
172 			addr6->sin6_port = relay_port;
173 #endif
174 		/* A server feature */
175 		if (bind_local_address6) {
176 			memcpy(&addr6->sin6_addr,
177 			       &local_address6,
178 			       sizeof(addr6->sin6_addr));
179 		}
180 		/* A client feature */
181 		if (linklocal6) {
182 			memcpy(&addr6->sin6_addr,
183 			       linklocal6,
184 			       sizeof(addr6->sin6_addr));
185 		}
186 		if (IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) {
187 			addr6->sin6_scope_id = if_nametoindex(info->name);
188 		}
189 #ifdef HAVE_SA_LEN
190 		addr6->sin6_len = sizeof(*addr6);
191 #endif
192 		name_len = sizeof(*addr6);
193 		domain = PF_INET6;
194 		if ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM) {
195 			*do_multicast = 0;
196 		}
197 		break;
198 #endif /* DHCPv6 */
199 
200 	case AF_INET:
201 	default:
202 		addr = (struct sockaddr_in *)&name;
203 		addr->sin_family = AF_INET;
204 		addr->sin_port = relay_port ? relay_port : local_port;
205 		memcpy(&addr->sin_addr,
206 		       &local_address,
207 		       sizeof(addr->sin_addr));
208 #ifdef HAVE_SA_LEN
209 		addr->sin_len = sizeof(*addr);
210 #endif
211 		name_len = sizeof(*addr);
212 		domain = PF_INET;
213 		break;
214 	}
215 
216 	/* Make a socket... */
217 	sock = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
218 	if (sock < 0) {
219 		log_fatal("Can't create dhcp socket: %m");
220 	}
221 
222 	/* Set the REUSEADDR option so that we don't fail to start if
223 	   we're being restarted. */
224 	flag = 1;
225 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
226 			(char *)&flag, sizeof(flag)) < 0) {
227 		log_fatal("Can't set SO_REUSEADDR option on dhcp socket: %m");
228 	}
229 
230 	/* Set the BROADCAST option so that we can broadcast DHCP responses.
231 	   We shouldn't do this for fallback devices, and we can detect that
232 	   a device is a fallback because it has no ifp structure. */
233 	if (info->ifp &&
234 	    (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
235 			 (char *)&flag, sizeof(flag)) < 0)) {
236 		log_fatal("Can't set SO_BROADCAST option on dhcp socket: %m");
237 	}
238 
239 #if defined(DHCPv6) && defined(SO_REUSEPORT)
240 	/*
241 	 * We only set SO_REUSEPORT on AF_INET6 sockets, so that multiple
242 	 * daemons can bind to their own sockets and get data for their
243 	 * respective interfaces.  This does not (and should not) affect
244 	 * DHCPv4 sockets; we can't yet support BSD sockets well, much
245 	 * less multiple sockets. Make sense only with multicast.
246 	 * RedHat defines SO_REUSEPORT with a kernel which does not support
247 	 * it and returns ENOPROTOOPT so in this case ignore the error.
248 	 */
249 	if ((local_family == AF_INET6) && *do_multicast) {
250 		flag = 1;
251 		if ((setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
252 			        (char *)&flag, sizeof(flag)) < 0) &&
253 		    (errno != ENOPROTOOPT)) {
254 			log_fatal("Can't set SO_REUSEPORT option on dhcp "
255 				  "socket: %m");
256 		}
257 	}
258 #endif
259 
260 	/* Bind the socket to this interface's IP address. */
261 	if (bind(sock, (struct sockaddr *)&name, name_len) < 0) {
262 		log_error("Can't bind to dhcp address: %m");
263 		log_error("Please make sure there is no other dhcp server");
264 		log_error("running and that there's no entry for dhcp or");
265 		log_error("bootp in /etc/inetd.conf.   Also make sure you");
266 		log_error("are not running HP JetAdmin software, which");
267 		log_fatal("includes a bootp server.");
268 	}
269 
270 #if defined(SO_BINDTODEVICE)
271 	/* Bind this socket to this interface. */
272 	if ((local_family != AF_INET6) && (info->ifp != NULL) &&
273 	    setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
274 			(char *)(info -> ifp), sizeof(*(info -> ifp))) < 0) {
275 		log_fatal("setsockopt: SO_BINDTODEVICE: %m");
276 	}
277 #endif
278 
279 	/* IP_BROADCAST_IF instructs the kernel which interface to send
280 	 * IP packets whose destination address is 255.255.255.255.  These
281 	 * will be treated as subnet broadcasts on the interface identified
282 	 * by ip address (info -> primary_address).  This is only known to
283 	 * be defined in SCO system headers, and may not be defined in all
284 	 * releases.
285 	 */
286 #if defined(SCO) && defined(IP_BROADCAST_IF)
287         if (info->address_count &&
288 	    setsockopt(sock, IPPROTO_IP, IP_BROADCAST_IF, &info->addresses[0],
289 		       sizeof(info->addresses[0])) < 0)
290 		log_fatal("Can't set IP_BROADCAST_IF on dhcp socket: %m");
291 #endif
292 
293 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO)  && defined(USE_V4_PKTINFO)
294 	/*
295 	 * If we turn on IP_RECVPKTINFO we will be able to receive
296 	 * the interface index information of the received packet.
297 	 */
298 	if (family == AF_INET) {
299 		int on = 1;
300 		if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO,
301 		               &on, sizeof(on)) != 0) {
302 			log_fatal("setsockopt: IPV_RECVPKTINFO: %m");
303 		}
304 	}
305 #endif
306 
307 #ifdef DHCPv6
308 	/*
309 	 * If we turn on IPV6_PKTINFO, we will be able to receive
310 	 * additional information, such as the destination IP address.
311 	 * We need this to spot unicast packets.
312 	 */
313 	if (family == AF_INET6) {
314 		int on = 1;
315 #ifdef IPV6_RECVPKTINFO
316 		/* RFC3542 */
317 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
318 		               &on, sizeof(on)) != 0) {
319 			log_fatal("setsockopt: IPV6_RECVPKTINFO: %m");
320 		}
321 #else
322 		/* RFC2292 */
323 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
324 		               &on, sizeof(on)) != 0) {
325 			log_fatal("setsockopt: IPV6_PKTINFO: %m");
326 		}
327 #endif
328 	}
329 
330 #endif /* DHCPv6 */
331 
332 	return sock;
333 }
334 
335 #ifdef DHCPv6
336 void set_multicast_hop_limit(struct interface_info* info, int hop_limit) {
337 	if (setsockopt(info->wfdesc, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
338 		       &hop_limit, sizeof(int)) < 0) {
339 		log_fatal("setMulticaseHopLimit: IPV6_MULTICAST_HOPS: %m");
340 	}
341 
342 	log_debug("Setting hop count limit to %d for interface %s",
343 		  hop_limit, info->name);
344 
345 }
346 #endif /* DHCPv6 */
347 
348 #endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE || USE_SOCKET_FALLBACK */
349 
350 #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
351 void if_register_send (info)
352 	struct interface_info *info;
353 {
354 #ifndef USE_SOCKET_RECEIVE
355 	info->wfdesc = if_register_socket(info, AF_INET, 0, NULL);
356 	/* If this is a normal IPv4 address, get the hardware address. */
357 	if (strcmp(info->name, "fallback") != 0)
358 		get_hw_addr(info->name, &info->hw_address);
359 #if defined (USE_SOCKET_FALLBACK)
360 	/* Fallback only registers for send, but may need to receive as
361 	   well. */
362 	info->rfdesc = info->wfdesc;
363 #endif
364 #else
365 	info->wfdesc = info->rfdesc;
366 #endif
367 	if (!quiet_interface_discovery)
368 		log_info ("Sending on   Socket/%s%s%s",
369 		      info->name,
370 		      (info->shared_network ? "/" : ""),
371 		      (info->shared_network ?
372 		       info->shared_network->name : ""));
373 }
374 
375 #if defined (USE_SOCKET_SEND)
376 void if_deregister_send (info)
377 	struct interface_info *info;
378 {
379 #ifndef USE_SOCKET_RECEIVE
380 	close (info -> wfdesc);
381 #endif
382 	info -> wfdesc = -1;
383 
384 	if (!quiet_interface_discovery)
385 		log_info ("Disabling output on Socket/%s%s%s",
386 		      info -> name,
387 		      (info -> shared_network ? "/" : ""),
388 		      (info -> shared_network ?
389 		       info -> shared_network -> name : ""));
390 }
391 #endif /* USE_SOCKET_SEND */
392 #endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */
393 
394 #ifdef USE_SOCKET_RECEIVE
395 void if_register_receive (info)
396 	struct interface_info *info;
397 {
398 
399 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
400 	if (global_v4_socket_references == 0) {
401 		global_v4_socket = if_register_socket(info, AF_INET, 0, NULL);
402 		if (global_v4_socket < 0) {
403 			/*
404 			 * if_register_socket() fatally logs if it fails to
405 			 * create a socket, this is just a sanity check.
406 			 */
407 			log_fatal("Failed to create AF_INET socket %s:%d",
408 				  MDL);
409 		}
410 	}
411 
412 	info->rfdesc = global_v4_socket;
413 	global_v4_socket_references++;
414 #else
415 	/* If we're using the socket API for sending and receiving,
416 	   we don't need to register this interface twice. */
417 	info->rfdesc = if_register_socket(info, AF_INET, 0, NULL);
418 #endif /* IP_PKTINFO... */
419 	/* If this is a normal IPv4 address, get the hardware address. */
420 	if (strcmp(info->name, "fallback") != 0)
421 		get_hw_addr(info->name, &info->hw_address);
422 
423 	if (!quiet_interface_discovery)
424 		log_info ("Listening on Socket/%s%s%s",
425 		      info->name,
426 		      (info->shared_network ? "/" : ""),
427 		      (info->shared_network ?
428 		       info->shared_network->name : ""));
429 }
430 
431 void if_deregister_receive (info)
432 	struct interface_info *info;
433 {
434 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
435 	/* Dereference the global v4 socket. */
436 	if ((info->rfdesc == global_v4_socket) &&
437 	    (global_v4_socket_references > 0)) {
438 		global_v4_socket_references--;
439 		info->rfdesc = -1;
440 	} else {
441 		log_fatal("Impossible condition at %s:%d", MDL);
442 	}
443 
444 	if (global_v4_socket_references == 0) {
445 		close(global_v4_socket);
446 		global_v4_socket = -1;
447 	}
448 #else
449 	close(info->rfdesc);
450 	info->rfdesc = -1;
451 #endif /* IP_PKTINFO... */
452 	if (!quiet_interface_discovery)
453 		log_info ("Disabling input on Socket/%s%s%s",
454 		      info -> name,
455 		      (info -> shared_network ? "/" : ""),
456 		      (info -> shared_network ?
457 		       info -> shared_network -> name : ""));
458 }
459 #endif /* USE_SOCKET_RECEIVE */
460 
461 
462 #ifdef DHCPv6
463 /*
464  * This function joins the interface to DHCPv6 multicast groups so we will
465  * receive multicast messages.
466  */
467 static void
468 if_register_multicast(struct interface_info *info) {
469 	int sock = info->rfdesc;
470 	struct ipv6_mreq mreq;
471 
472 	if (inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
473 		      &mreq.ipv6mr_multiaddr) <= 0) {
474 		log_fatal("inet_pton: unable to convert '%s'",
475 			  All_DHCP_Relay_Agents_and_Servers);
476 	}
477 	mreq.ipv6mr_interface = if_nametoindex(info->name);
478 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
479 		       &mreq, sizeof(mreq)) < 0) {
480 		log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
481 	}
482 
483 	/*
484 	 * The relay agent code sets the streams so you know which way
485 	 * is up and down.  But a relay agent shouldn't join to the
486 	 * Server address, or else you get fun loops.  So up or down
487 	 * doesn't matter, we're just using that config to sense this is
488 	 * a relay agent.
489 	 */
490 	if ((info->flags & INTERFACE_STREAMS) == 0) {
491 		if (inet_pton(AF_INET6, All_DHCP_Servers,
492 			      &mreq.ipv6mr_multiaddr) <= 0) {
493 			log_fatal("inet_pton: unable to convert '%s'",
494 				  All_DHCP_Servers);
495 		}
496 		mreq.ipv6mr_interface = if_nametoindex(info->name);
497 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
498 			       &mreq, sizeof(mreq)) < 0) {
499 			log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
500 		}
501 	}
502 }
503 
504 void
505 if_register6(struct interface_info *info, int do_multicast) {
506 	/* Bounce do_multicast to a stack variable because we may change it. */
507 	int req_multi = do_multicast;
508 
509 	if (no_global_v6_socket) {
510 		log_fatal("Impossible condition at %s:%d", MDL);
511 	}
512 
513 #if defined(RELAY_PORT)
514 	if (!relay_port ||
515 	    ((info->flags & INTERFACE_STREAMS) == INTERFACE_DOWNSTREAM)) {
516 #endif
517 	if (global_v6_socket_references == 0) {
518 		global_v6_socket = if_register_socket(info, AF_INET6,
519 						      &req_multi, NULL);
520 		if (global_v6_socket < 0) {
521 			/*
522 			 * if_register_socket() fatally logs if it fails to
523 			 * create a socket, this is just a sanity check.
524 			 */
525 			log_fatal("Impossible condition at %s:%d", MDL);
526 		} else if (bind_local_address6) {
527 			char addr6_str[INET6_ADDRSTRLEN];
528 
529 			if (inet_ntop(AF_INET6,
530 				      &local_address6,
531 				      addr6_str,
532 				      sizeof(addr6_str)) == NULL) {
533 				log_fatal("inet_ntop: unable to convert "
534 					  "local-address6");
535 			}
536 			log_info("Bound to [%s]:%d",
537 				 addr6_str,
538 				 (int) ntohs(local_port));
539 		} else {
540 			log_info("Bound to *:%d", (int) ntohs(local_port));
541 		}
542 	}
543 
544 	info->rfdesc = global_v6_socket;
545 	info->wfdesc = global_v6_socket;
546 	global_v6_socket_references++;
547 
548 #if defined(RELAY_PORT)
549 	} else {
550 	/*
551 	 * If relay port is defined, we need to register one
552 	 * IPv6 UPD socket to handle upstream server or relay agent
553 	 * with a non-547 UDP local port.
554 	 */
555 	if ((relay_port_v6_socket_references == 0) &&
556 	    ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM)) {
557 		relay_port_v6_socket = if_register_socket(info, AF_INET6,
558 							  &req_multi, NULL);
559 		if (relay_port_v6_socket < 0) {
560 			log_fatal("Impossible condition at %s:%d", MDL);
561 		} else {
562 			log_info("Bound to relay port *:%d",
563 				 (int) ntohs(relay_port));
564 		}
565 	}
566 	info->rfdesc = relay_port_v6_socket;
567 	info->wfdesc = relay_port_v6_socket;
568 	relay_port_v6_socket_references++;
569 	}
570 #endif
571 
572 	if (req_multi)
573 		if_register_multicast(info);
574 
575 	get_hw_addr(info->name, &info->hw_address);
576 
577 	if (!quiet_interface_discovery) {
578 		if (info->shared_network != NULL) {
579 			log_info("Listening on Socket/%d/%s/%s",
580 				 global_v6_socket, info->name,
581 				 info->shared_network->name);
582 			log_info("Sending on   Socket/%d/%s/%s",
583 				 global_v6_socket, info->name,
584 				 info->shared_network->name);
585 		} else {
586 			log_info("Listening on Socket/%s", info->name);
587 			log_info("Sending on   Socket/%s", info->name);
588 		}
589 	}
590 }
591 
592 /*
593  * Register an IPv6 socket bound to the link-local address of
594  * the argument interface (used by clients on a multiple interface box,
595  * vs. a server or a relay using the global IPv6 socket and running
596  * *only* in a single instance).
597  */
598 void
599 if_register_linklocal6(struct interface_info *info) {
600 	int sock;
601 	int count;
602 	struct in6_addr *addr6 = NULL;
603 	int req_multi = 0;
604 
605 	if (global_v6_socket >= 0) {
606 		log_fatal("Impossible condition at %s:%d", MDL);
607 	}
608 
609 	no_global_v6_socket = 1;
610 
611 	/* get the (?) link-local address */
612 	for (count = 0; count < info->v6address_count; count++) {
613 		addr6 = &info->v6addresses[count];
614 		if (IN6_IS_ADDR_LINKLOCAL(addr6))
615 			break;
616 	}
617 
618 	if (!addr6) {
619 		log_fatal("no link-local IPv6 address for %s", info->name);
620 	}
621 
622 	sock = if_register_socket(info, AF_INET6, &req_multi, addr6);
623 
624 	if (sock < 0) {
625 		log_fatal("if_register_socket for %s fails", info->name);
626 	}
627 
628 	info->rfdesc = sock;
629 	info->wfdesc = sock;
630 
631 	get_hw_addr(info->name, &info->hw_address);
632 
633 	if (!quiet_interface_discovery) {
634 		if (info->shared_network != NULL) {
635 			log_info("Listening on Socket/%d/%s/%s",
636 				 global_v6_socket, info->name,
637 				 info->shared_network->name);
638 			log_info("Sending on   Socket/%d/%s/%s",
639 				 global_v6_socket, info->name,
640 				 info->shared_network->name);
641 		} else {
642 			log_info("Listening on Socket/%s", info->name);
643 			log_info("Sending on   Socket/%s", info->name);
644 		}
645 	}
646 }
647 
648 void
649 if_deregister6(struct interface_info *info) {
650 	/* client case */
651 	if (no_global_v6_socket) {
652 		close(info->rfdesc);
653 		info->rfdesc = -1;
654 		info->wfdesc = -1;
655 	} else if ((info->rfdesc == global_v6_socket) &&
656 		   (info->wfdesc == global_v6_socket) &&
657 		   (global_v6_socket_references > 0)) {
658 		/* Dereference the global v6 socket. */
659 		global_v6_socket_references--;
660 		info->rfdesc = -1;
661 		info->wfdesc = -1;
662 #if defined(RELAY_PORT)
663 	} else if (relay_port &&
664 		   (info->rfdesc == relay_port_v6_socket) &&
665 		   (info->wfdesc == relay_port_v6_socket) &&
666 		   (relay_port_v6_socket_references > 0)) {
667 		/* Dereference the relay port v6 socket. */
668 		relay_port_v6_socket_references--;
669 		info->rfdesc = -1;
670 		info->wfdesc = -1;
671 #endif
672 	} else {
673 		log_fatal("Impossible condition at %s:%d", MDL);
674 	}
675 
676 	if (!quiet_interface_discovery) {
677 		if (info->shared_network != NULL) {
678 			log_info("Disabling input on  Socket/%s/%s", info->name,
679 		       		 info->shared_network->name);
680 			log_info("Disabling output on Socket/%s/%s", info->name,
681 		       		 info->shared_network->name);
682 		} else {
683 			log_info("Disabling input on  Socket/%s", info->name);
684 			log_info("Disabling output on Socket/%s", info->name);
685 		}
686 	}
687 
688 	if (!no_global_v6_socket) {
689 		if (global_v6_socket_references == 0) {
690 			close(global_v6_socket);
691 			global_v6_socket = -1;
692 
693 			log_info("Unbound from *:%d",
694 				 (int) ntohs(local_port));
695 		}
696 #if defined(RELAY_PORT)
697 		if (relay_port && (relay_port_v6_socket_references == 0)) {
698 			close(relay_port_v6_socket);
699 			relay_port_v6_socket = -1;
700 
701 			log_info("Unbound from relay port *:%d",
702 				 (int) ntohs(relay_port));
703 		}
704 #endif
705 	}
706 }
707 #endif /* DHCPv6 */
708 
709 #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
710 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
711 	struct interface_info *interface;
712 	struct packet *packet;
713 	struct dhcp_packet *raw;
714 	size_t len;
715 	struct in_addr from;
716 	struct sockaddr_in *to;
717 	struct hardware *hto;
718 {
719 	int result;
720 #ifdef IGNORE_HOSTUNREACH
721 	int retry = 0;
722 	do {
723 #endif
724 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
725 		struct in_pktinfo pktinfo;
726 
727 		if (interface->ifp != NULL) {
728 			memset(&pktinfo, 0, sizeof (pktinfo));
729 			pktinfo.ipi_ifindex = interface->ifp->ifr_index;
730 			if (setsockopt(interface->wfdesc, IPPROTO_IP,
731 				       IP_PKTINFO, (char *)&pktinfo,
732 				       sizeof(pktinfo)) < 0)
733 				log_fatal("setsockopt: IP_PKTINFO: %m");
734 		}
735 #endif
736 		result = sendto (interface -> wfdesc, (char *)raw, len, 0,
737 				 (struct sockaddr *)to, sizeof *to);
738 #ifdef IGNORE_HOSTUNREACH
739 	} while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) &&
740 		 result < 0 &&
741 		 (errno == EHOSTUNREACH ||
742 		  errno == ECONNREFUSED) &&
743 		 retry++ < 10);
744 #endif
745 	if (result < 0) {
746 		log_error ("send_packet: %m");
747 		if (errno == ENETUNREACH)
748 			log_error ("send_packet: please consult README file%s",
749 				   " regarding broadcast address.");
750 	}
751 	return result;
752 }
753 
754 #endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */
755 
756 #ifdef DHCPv6
757 /*
758  * Solaris 9 is missing the CMSG_LEN and CMSG_SPACE macros, so we will
759  * synthesize them (based on the BIND 9 technique).
760  */
761 
762 #ifndef CMSG_LEN
763 static size_t CMSG_LEN(size_t len) {
764 	size_t hdrlen;
765 	/*
766 	 * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
767 	 * is correct.
768 	 */
769 	hdrlen = (size_t)CMSG_DATA(((struct cmsghdr *)NULL));
770 	return hdrlen + len;
771 }
772 #endif /* !CMSG_LEN */
773 
774 #ifndef CMSG_SPACE
775 static size_t CMSG_SPACE(size_t len) {
776 	struct msghdr msg;
777 	struct cmsghdr *cmsgp;
778 
779 	/*
780 	 * XXX: The buffer length is an ad-hoc value, but should be enough
781 	 * in a practical sense.
782 	 */
783 	union {
784 		struct cmsghdr cmsg_sizer;
785 		u_int8_t pktinfo_sizer[sizeof(struct cmsghdr) + 1024];
786 	} dummybuf;
787 
788 	memset(&msg, 0, sizeof(msg));
789 	msg.msg_control = &dummybuf;
790 	msg.msg_controllen = sizeof(dummybuf);
791 
792 	cmsgp = (struct cmsghdr *)&dummybuf;
793 	cmsgp->cmsg_len = CMSG_LEN(len);
794 
795 	cmsgp = CMSG_NXTHDR(&msg, cmsgp);
796 	if (cmsgp != NULL) {
797 		return (char *)cmsgp - (char *)msg.msg_control;
798 	} else {
799 		return 0;
800 	}
801 }
802 #endif /* !CMSG_SPACE */
803 
804 #endif /* DHCPv6 */
805 
806 #if defined(DHCPv6) || \
807 	(defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
808 	 defined(USE_V4_PKTINFO))
809 /*
810  * For both send_packet6() and receive_packet6() we need to allocate
811  * space for the cmsg header information.  We do this once and reuse
812  * the buffer.  We also need the control buf for send_packet() and
813  * receive_packet() when we use a single socket and IP_PKTINFO to
814  * send the packet out the correct interface.
815  */
816 static void   *control_buf = NULL;
817 static size_t  control_buf_len = 0;
818 
819 static void
820 allocate_cmsg_cbuf(void) {
821 	control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
822 	control_buf = dmalloc(control_buf_len, MDL);
823 	return;
824 }
825 #endif /* DHCPv6, IP_PKTINFO ... */
826 
827 #ifdef DHCPv6
828 /*
829  * For both send_packet6() and receive_packet6() we need to use the
830  * sendmsg()/recvmsg() functions rather than the simpler send()/recv()
831  * functions.
832  *
833  * In the case of send_packet6(), we need to do this in order to insure
834  * that the reply packet leaves on the same interface that it arrived
835  * on.
836  *
837  * In the case of receive_packet6(), we need to do this in order to
838  * get the IP address the packet was sent to. This is used to identify
839  * whether a packet is multicast or unicast.
840  *
841  * Helpful man pages: recvmsg, readv (talks about the iovec stuff), cmsg.
842  *
843  * Also see the sections in RFC 3542 about IPV6_PKTINFO.
844  */
845 
846 /* Send an IPv6 packet */
847 ssize_t send_packet6(struct interface_info *interface,
848 		     const unsigned char *raw, size_t len,
849 		     struct sockaddr_in6 *to) {
850 	struct msghdr m;
851 	struct iovec v;
852 	struct sockaddr_in6 dst;
853 	int result;
854 	struct in6_pktinfo *pktinfo;
855 	struct cmsghdr *cmsg;
856 	unsigned int ifindex;
857 
858 	/*
859 	 * If necessary allocate space for the control message header.
860 	 * The space is common between send and receive.
861 	 */
862 
863 	if (control_buf == NULL) {
864 		allocate_cmsg_cbuf();
865 		if (control_buf == NULL) {
866 			log_error("send_packet6: unable to allocate cmsg header");
867 			return(ENOMEM);
868 		}
869 	}
870 	memset(control_buf, 0, control_buf_len);
871 
872 	/*
873 	 * Initialize our message header structure.
874 	 */
875 	memset(&m, 0, sizeof(m));
876 
877 	/*
878 	 * Set the target address we're sending to.
879 	 * Enforce the scope ID for bogus BSDs.
880 	 */
881 	memcpy(&dst, to, sizeof(dst));
882 	m.msg_name = &dst;
883 	m.msg_namelen = sizeof(dst);
884 	ifindex = if_nametoindex(interface->name);
885 	if (no_global_v6_socket)
886 		dst.sin6_scope_id = ifindex;
887 
888 	/*
889 	 * Set the data buffer we're sending. (Using this wacky
890 	 * "scatter-gather" stuff... we only have a single chunk
891 	 * of data to send, so we declare a single vector entry.)
892 	 */
893 	v.iov_base = (char *)raw;
894 	v.iov_len = len;
895 	m.msg_iov = &v;
896 	m.msg_iovlen = 1;
897 
898 	/*
899 	 * Setting the interface is a bit more involved.
900 	 *
901 	 * We have to create a "control message", and set that to
902 	 * define the IPv6 packet information. We could set the
903 	 * source address if we wanted, but we can safely let the
904 	 * kernel decide what that should be.
905 	 */
906 	m.msg_control = control_buf;
907 	m.msg_controllen = control_buf_len;
908 	cmsg = CMSG_FIRSTHDR(&m);
909 	INSIST(cmsg != NULL);
910 	cmsg->cmsg_level = IPPROTO_IPV6;
911 	cmsg->cmsg_type = IPV6_PKTINFO;
912 	cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
913 	pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
914 	memset(pktinfo, 0, sizeof(*pktinfo));
915 	pktinfo->ipi6_addr = local_address6;
916 	pktinfo->ipi6_ifindex = ifindex;
917 
918 	result = sendmsg(interface->wfdesc, &m, 0);
919 	if (result < 0) {
920 		log_error("send_packet6: %m");
921 	}
922 	return result;
923 }
924 #endif /* DHCPv6 */
925 
926 #ifdef USE_SOCKET_RECEIVE
927 ssize_t receive_packet (interface, buf, len, from, hfrom)
928 	struct interface_info *interface;
929 	unsigned char *buf;
930 	size_t len;
931 	struct sockaddr_in *from;
932 	struct hardware *hfrom;
933 {
934 #if !(defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO))
935 	SOCKLEN_T flen = sizeof *from;
936 #endif
937 	int result;
938 
939 	/*
940 	 * The normal Berkeley socket interface doesn't give us any way
941 	 * to know what hardware interface we received the message on,
942 	 * but we should at least make sure the structure is emptied.
943 	 */
944 	memset(hfrom, 0, sizeof(*hfrom));
945 
946 #ifdef IGNORE_HOSTUNREACH
947 	int retry = 0;
948 	do {
949 #endif
950 
951 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
952 	struct msghdr m;
953 	struct iovec v;
954 	struct cmsghdr *cmsg;
955 	struct in_pktinfo *pktinfo;
956 	unsigned int ifindex;
957 
958 	/*
959 	 * If necessary allocate space for the control message header.
960 	 * The space is common between send and receive.
961 	 */
962 	if (control_buf == NULL) {
963 		allocate_cmsg_cbuf();
964 		if (control_buf == NULL) {
965 			log_error("receive_packet: unable to allocate cmsg "
966 				  "header");
967 			return(ENOMEM);
968 		}
969 	}
970 	memset(control_buf, 0, control_buf_len);
971 
972 	/*
973 	 * Initialize our message header structure.
974 	 */
975 	memset(&m, 0, sizeof(m));
976 
977 	/*
978 	 * Point so we can get the from address.
979 	 */
980 	m.msg_name = from;
981 	m.msg_namelen = sizeof(*from);
982 
983 	/*
984 	 * Set the data buffer we're receiving. (Using this wacky
985 	 * "scatter-gather" stuff... but we that doesn't really make
986 	 * sense for us, so we use a single vector entry.)
987 	 */
988 	v.iov_base = buf;
989 	v.iov_len = len;
990 	m.msg_iov = &v;
991 	m.msg_iovlen = 1;
992 
993 	/*
994 	 * Getting the interface is a bit more involved.
995 	 *
996 	 * We set up some space for a "control message". We have
997 	 * previously asked the kernel to give us packet
998 	 * information (when we initialized the interface), so we
999 	 * should get the interface index from that.
1000 	 */
1001 	m.msg_control = control_buf;
1002 	m.msg_controllen = control_buf_len;
1003 
1004 	result = recvmsg(interface->rfdesc, &m, 0);
1005 
1006 	if (result >= 0) {
1007 		/*
1008 		 * If we did read successfully, then we need to loop
1009 		 * through the control messages we received and
1010 		 * find the one with our inteface index.
1011 		 */
1012 		cmsg = CMSG_FIRSTHDR(&m);
1013 		while (cmsg != NULL) {
1014 			if ((cmsg->cmsg_level == IPPROTO_IP) &&
1015 			    (cmsg->cmsg_type == IP_PKTINFO)) {
1016 				pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
1017 				ifindex = pktinfo->ipi_ifindex;
1018 				/*
1019 				 * We pass the ifindex back to the caller
1020 				 * using the unused hfrom parameter avoiding
1021 				 * interface changes between sockets and
1022 				 * the discover code.
1023 				 */
1024 				memcpy(hfrom->hbuf, &ifindex, sizeof(ifindex));
1025 				return (result);
1026 			}
1027 			cmsg = CMSG_NXTHDR(&m, cmsg);
1028 		}
1029 
1030 		/*
1031 		 * We didn't find the necessary control message
1032 		 * flag it as an error
1033 		 */
1034 		result = -1;
1035 		errno = EIO;
1036 	}
1037 #else
1038 		result = recvfrom(interface -> rfdesc, (char *)buf, len, 0,
1039 				  (struct sockaddr *)from, &flen);
1040 #endif /* IP_PKTINFO ... */
1041 #ifdef IGNORE_HOSTUNREACH
1042 	} while (result < 0 &&
1043 		 (errno == EHOSTUNREACH ||
1044 		  errno == ECONNREFUSED) &&
1045 		 retry++ < 10);
1046 #endif
1047 	return (result);
1048 }
1049 
1050 #endif /* USE_SOCKET_RECEIVE */
1051 
1052 #ifdef DHCPv6
1053 ssize_t
1054 receive_packet6(struct interface_info *interface,
1055 		unsigned char *buf, size_t len,
1056 		struct sockaddr_in6 *from, struct in6_addr *to_addr,
1057 		unsigned int *if_idx)
1058 {
1059 	struct msghdr m;
1060 	struct iovec v;
1061 	int result;
1062 	struct cmsghdr *cmsg;
1063 	struct in6_pktinfo *pktinfo;
1064 
1065 	/*
1066 	 * If necessary allocate space for the control message header.
1067 	 * The space is common between send and receive.
1068 	 */
1069 	if (control_buf == NULL) {
1070 		allocate_cmsg_cbuf();
1071 		if (control_buf == NULL) {
1072 			log_error("receive_packet6: unable to allocate cmsg "
1073 				  "header");
1074 			return(ENOMEM);
1075 		}
1076 	}
1077 	memset(control_buf, 0, control_buf_len);
1078 
1079 	/*
1080 	 * Initialize our message header structure.
1081 	 */
1082 	memset(&m, 0, sizeof(m));
1083 
1084 	/*
1085 	 * Point so we can get the from address.
1086 	 */
1087 	m.msg_name = from;
1088 	m.msg_namelen = sizeof(*from);
1089 
1090 	/*
1091 	 * Set the data buffer we're receiving. (Using this wacky
1092 	 * "scatter-gather" stuff... but we that doesn't really make
1093 	 * sense for us, so we use a single vector entry.)
1094 	 */
1095 	v.iov_base = buf;
1096 	v.iov_len = len;
1097 	m.msg_iov = &v;
1098 	m.msg_iovlen = 1;
1099 
1100 	/*
1101 	 * Getting the interface is a bit more involved.
1102 	 *
1103 	 * We set up some space for a "control message". We have
1104 	 * previously asked the kernel to give us packet
1105 	 * information (when we initialized the interface), so we
1106 	 * should get the destination address from that.
1107 	 */
1108 	m.msg_control = control_buf;
1109 	m.msg_controllen = control_buf_len;
1110 
1111 	result = recvmsg(interface->rfdesc, &m, 0);
1112 
1113 	if (result >= 0) {
1114 		/*
1115 		 * If we did read successfully, then we need to loop
1116 		 * through the control messages we received and
1117 		 * find the one with our destination address.
1118 		 */
1119 		cmsg = CMSG_FIRSTHDR(&m);
1120 		while (cmsg != NULL) {
1121 			if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
1122 			    (cmsg->cmsg_type == IPV6_PKTINFO)) {
1123 				pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
1124 				*to_addr = pktinfo->ipi6_addr;
1125 				*if_idx = pktinfo->ipi6_ifindex;
1126 
1127 				return (result);
1128 			}
1129 			cmsg = CMSG_NXTHDR(&m, cmsg);
1130 		}
1131 
1132 		/*
1133 		 * We didn't find the necessary control message
1134 		 * flag is as an error
1135 		 */
1136 		result = -1;
1137 		errno = EIO;
1138 	}
1139 
1140 	return (result);
1141 }
1142 #endif /* DHCPv6 */
1143 
1144 #if defined (USE_SOCKET_FALLBACK)
1145 /* This just reads in a packet and silently discards it. */
1146 
1147 isc_result_t fallback_discard (object)
1148 	omapi_object_t *object;
1149 {
1150 	char buf [1540];
1151 	struct sockaddr_in from;
1152 	SOCKLEN_T flen = sizeof from;
1153 	int status;
1154 	struct interface_info *interface;
1155 
1156 	if (object -> type != dhcp_type_interface)
1157 		return DHCP_R_INVALIDARG;
1158 	interface = (struct interface_info *)object;
1159 
1160 	status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0,
1161 			   (struct sockaddr *)&from, &flen);
1162 #if defined (DEBUG)
1163 	/* Only report fallback discard errors if we're debugging. */
1164 	if (status < 0) {
1165 		log_error ("fallback_discard: %m");
1166 		return ISC_R_UNEXPECTED;
1167 	}
1168 #else
1169         /* ignore the fact that status value is never used */
1170         IGNORE_UNUSED(status);
1171 #endif
1172 	return ISC_R_SUCCESS;
1173 }
1174 #endif /* USE_SOCKET_FALLBACK */
1175 
1176 #if defined (USE_SOCKET_SEND)
1177 int can_unicast_without_arp (ip)
1178 	struct interface_info *ip;
1179 {
1180 	return 0;
1181 }
1182 
1183 int can_receive_unicast_unconfigured (ip)
1184 	struct interface_info *ip;
1185 {
1186 #if defined (SOCKET_CAN_RECEIVE_UNICAST_UNCONFIGURED)
1187 	return 1;
1188 #else
1189 	return 0;
1190 #endif
1191 }
1192 
1193 int supports_multiple_interfaces (ip)
1194 	struct interface_info *ip;
1195 {
1196 #if defined(SO_BINDTODEVICE) || \
1197 	(defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
1198 	 defined(USE_V4_PKTINFO))
1199 	return(1);
1200 #else
1201 	return(0);
1202 #endif
1203 }
1204 
1205 /* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise,
1206    do not. */
1207 
1208 void maybe_setup_fallback ()
1209 {
1210 #if defined (USE_SOCKET_FALLBACK)
1211 	isc_result_t status;
1212 	struct interface_info *fbi = (struct interface_info *)0;
1213 	if (setup_fallback (&fbi, MDL)) {
1214 		fbi -> wfdesc = if_register_socket (fbi, AF_INET, 0, NULL);
1215 		fbi -> rfdesc = fbi -> wfdesc;
1216 		log_info ("Sending on   Socket/%s%s%s",
1217 		      fbi -> name,
1218 		      (fbi -> shared_network ? "/" : ""),
1219 		      (fbi -> shared_network ?
1220 		       fbi -> shared_network -> name : ""));
1221 
1222 		status = omapi_register_io_object ((omapi_object_t *)fbi,
1223 						   if_readsocket, 0,
1224 						   fallback_discard, 0, 0);
1225 		if (status != ISC_R_SUCCESS)
1226 			log_fatal ("Can't register I/O handle for %s: %s",
1227 				   fbi -> name, isc_result_totext (status));
1228 		interface_dereference (&fbi, MDL);
1229 	}
1230 #endif
1231 }
1232 
1233 
1234 #if defined(sun) && defined(USE_V4_PKTINFO)
1235 /* This code assumes the existence of SIOCGLIFHWADDR */
1236 void
1237 get_hw_addr(const char *name, struct hardware *hw) {
1238 	struct sockaddr_dl *dladdrp;
1239 	int sock, i;
1240 	struct lifreq lifr;
1241 
1242 	memset(&lifr, 0, sizeof (lifr));
1243 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1244 	/*
1245 	 * Check if the interface is a virtual or IPMP interface - in those
1246 	 * cases it has no hw address, so generate a random one.
1247 	 */
1248 	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
1249 	    ioctl(sock, SIOCGLIFFLAGS, &lifr) < 0) {
1250 		if (sock != -1)
1251 			(void) close(sock);
1252 
1253 #ifdef DHCPv6
1254 		/*
1255 		 * If approrpriate try this with an IPv6 socket
1256 		 */
1257 		if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) >= 0 &&
1258 		    ioctl(sock, SIOCGLIFFLAGS, &lifr) >= 0) {
1259 			goto flag_check;
1260 		}
1261 		if (sock != -1)
1262 			(void) close(sock);
1263 #endif
1264 		log_fatal("Couldn't get interface flags for %s: %m", name);
1265 
1266 	}
1267 
1268  flag_check:
1269 	if (lifr.lifr_flags & (IFF_VIRTUAL|IFF_IPMP)) {
1270 		hw->hlen = sizeof (hw->hbuf);
1271 		srandom((long)gethrtime());
1272 
1273 		hw->hbuf[0] = HTYPE_IPMP;
1274 		for (i = 1; i < hw->hlen; ++i) {
1275 			hw->hbuf[i] = random() % 256;
1276 		}
1277 
1278 		if (sock != -1)
1279 			(void) close(sock);
1280 		return;
1281 	}
1282 
1283 	if (ioctl(sock, SIOCGLIFHWADDR, &lifr) < 0)
1284 		log_fatal("Couldn't get interface hardware address for %s: %m",
1285 			  name);
1286 	dladdrp = (struct sockaddr_dl *)&lifr.lifr_addr;
1287 	hw->hlen = dladdrp->sdl_alen+1;
1288 	switch (dladdrp->sdl_type) {
1289 		case DL_CSMACD: /* IEEE 802.3 */
1290 		case DL_ETHER:
1291 			hw->hbuf[0] = HTYPE_ETHER;
1292 			break;
1293 		case DL_TPR:
1294 			hw->hbuf[0] = HTYPE_IEEE802;
1295 			break;
1296 		case DL_FDDI:
1297 			hw->hbuf[0] = HTYPE_FDDI;
1298 			break;
1299 		case DL_IB:
1300 			hw->hbuf[0] = HTYPE_INFINIBAND;
1301 			break;
1302 		default:
1303 			log_fatal("%s: unsupported DLPI MAC type %lu", name,
1304 				  (unsigned long)dladdrp->sdl_type);
1305 	}
1306 
1307 	memcpy(hw->hbuf+1, LLADDR(dladdrp), hw->hlen-1);
1308 
1309 	if (sock != -1)
1310 		(void) close(sock);
1311 }
1312 #endif /* defined(sun) */
1313 
1314 #endif /* USE_SOCKET_SEND */
1315