This patch file was developed in-house to fix a Solaris specific bug. We are working with upstream, but it is unclear at this point whether or not they are going to accept it. This is a highly visible bug which many customers have encountered. diff -r 1680283c6725 common/socket.c --- a/common/socket.c Tue Jan 16 13:35:26 2018 -0800 +++ b/common/socket.c Tue Jan 16 17:55:37 2018 -0800 @@ -39,6 +39,9 @@ #include #include #include +#if defined (sun) +#include +#endif #if defined(sun) && defined(USE_V4_PKTINFO) #include @@ -87,6 +90,33 @@ static int once = 0; #endif /* !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK) */ +#if defined (sun) +int +setup_arp(struct interface_info *interface, struct in_addr ip_addr, + unsigned char *macaddr) +{ + struct xarpreq ar; + struct sockaddr_in *sin; + + (void) memset(&ar, 0, sizeof (ar)); + sin = (struct sockaddr_in *)&ar.xarp_pa; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = ip_addr.s_addr; + + ar.xarp_ha.sdl_alen = ETHERADDRL; + (void) memcpy(LLADDR(&ar.xarp_ha), macaddr, ar.xarp_ha.sdl_alen); + ar.xarp_ha.sdl_family = AF_LINK; + if (ioctl(interface->set_arp_socket, SIOCSXARP, (caddr_t)&ar) < 0) { + log_error("setup_arp: ioctl error for IP %s MAC %s", + inet_ntoa(ip_addr), ether_ntoa((const struct ether_addr *) + macaddr)); + return (1); + } + return (0); +} +#endif + + /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ @@ -340,6 +370,9 @@ #else info->wfdesc = info->rfdesc; #endif +#if defined(sun) + info->set_arp_socket = socket(AF_INET, SOCK_DGRAM, 0); +#endif if (!quiet_interface_discovery) log_info ("Sending on Socket/%s%s%s", info->name, @@ -356,6 +389,9 @@ close (info -> wfdesc); #endif info -> wfdesc = -1; +#if defined (sun) + close (info -> set_arp_socket); +#endif if (!quiet_interface_discovery) log_info ("Disabling output on Socket/%s%s%s", @@ -1091,7 +1127,11 @@ int can_unicast_without_arp (ip) struct interface_info *ip; { +#if defined (sun) + return 1; +#else return 0; +#endif } int can_receive_unicast_unconfigured (ip) diff -r 1680283c6725 includes/dhcpd.h --- a/includes/dhcpd.h Tue Jan 16 13:35:26 2018 -0800 +++ b/includes/dhcpd.h Tue Jan 16 17:55:37 2018 -0800 @@ -1378,6 +1378,9 @@ int configured; /* If set to 1, interface has at least * one valid IP address. */ +#if defined (sun) + int set_arp_socket; /* IOCTL socket to set entry in cache */ +#endif u_int32_t flags; /* Control flags... */ #define INTERFACE_REQUESTED 1 #define INTERFACE_AUTOMATIC 2 @@ -2608,6 +2611,10 @@ struct sockaddr_in6 *, struct hardware *); #endif +#if defined (sun) +int setup_arp(struct interface_info *, struct in_addr, unsigned char *); +#endif + #ifdef USE_SOCKET_SEND void if_reinitialize_send (struct interface_info *); void if_register_send (struct interface_info *); diff -r 1680283c6725 relay/dhcrelay.c --- a/relay/dhcrelay.c Tue Jan 16 13:35:26 2018 -0800 +++ b/relay/dhcrelay.c Tue Jan 16 17:55:37 2018 -0800 @@ -759,6 +759,13 @@ to.sin_addr = packet->yiaddr; to.sin_port = remote_port; +#if defined (sun) + if (setup_arp(out, packet->yiaddr, packet->chaddr)) { + log_error("do_relay4 : Set arp entry failed"); + return; + } +#endif + /* and hardware address is not broadcast */ htop = &hto; } else { diff -r 1680283c6725 server/bootp.c --- a/server/bootp.c Tue Jan 16 13:35:26 2018 -0800 +++ b/server/bootp.c Tue Jan 16 17:55:37 2018 -0800 @@ -437,7 +437,12 @@ can_unicast_without_arp (packet -> interface)) { to.sin_addr = raw.yiaddr; to.sin_port = remote_port; - +#if defined (__sun) + if (setup_arp(packet->interface, raw.yiaddr, raw.chaddr)) { + log_error("bootp : Set arp entry failed"); + goto out; + } +#endif /* Otherwise, broadcast it on the local network. */ } else { to.sin_addr = limited_broadcast; diff -r 1680283c6725 server/dhcp.c --- a/server/dhcp.c Tue Jan 16 13:35:26 2018 -0800 +++ b/server/dhcp.c Tue Jan 16 17:55:37 2018 -0800 @@ -30,6 +30,8 @@ #include #include #include +#include +#include static void maybe_return_agent_options(struct packet *packet, struct option_state *options); @@ -3991,7 +3993,12 @@ can_unicast_without_arp (state -> ip)) { to.sin_addr = raw.yiaddr; to.sin_port = remote_port; - +#if defined (sun) + if (setup_arp(state->ip, raw.yiaddr, raw.chaddr)) { + log_error("dhcp_reply : Set arp entry failed"); + goto err_out; + } +#endif /* Otherwise, broadcast it on the local network. */ } else { to.sin_addr = limited_broadcast; @@ -4013,7 +4020,9 @@ /* Free all of the entries in the option_state structure now that we're done with them. */ - +#if defined (sun) +err_out: +#endif free_lease_state (state, MDL); lease -> state = (struct lease_state *)0; }