If there are multiple datalinks configured with IP addresses from the same subnet, then the datalink to which an on-link device's ARP entry will be associated depends on the order in which these datalinks were plumbed with IP addresses. In that, the datalink that was plumbed for IP last will have the ARP entry associated against it. To avoid, this we need to use SIOCSXARP ioctl to specify the exact datalink. This patch was developed in-house. Since it is Solaris-specific it is not suitable for upstream. diff --git a/src/dhcp.c b/src/dhcp.c index 97324f2..24c6ad0 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -440,17 +440,24 @@ void dhcp_packet(time_t now, int pxe_fd) else { /* unicast to unconfigured client. Inject mac address direct into ARP cache. - Note that this only works for ethernet on solaris, because we use SIOCSARP - and not SIOCSXARP, which would be perfect, except that it returns ENXIO - mysteriously. Bah. Fall back to broadcast for other net types. */ - struct arpreq req; + Fall back to broadcast for other net types. */ + struct xarpreq xreq; + int ifnamsz = strlen(ifr.ifr_name); + + dest.sin_family = AF_INET; dest.sin_addr = mess->yiaddr; dest.sin_port = htons(daemon->dhcp_client_port); - *((struct sockaddr_in *)&req.arp_pa) = dest; - req.arp_ha.sa_family = AF_UNSPEC; - memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen); - req.arp_flags = ATF_COM; - ioctl(daemon->dhcpfd, SIOCSARP, &req); + *((struct sockaddr_in *)&xreq.xarp_pa) = dest; + xreq.xarp_ha.sdl_nlen = ifnamsz; + memcpy(xreq.xarp_ha.sdl_data, ifr.ifr_name, ifnamsz); + xreq.xarp_ha.sdl_family = AF_LINK; + xreq.xarp_ha.sdl_index = iface_index; + /* 6 corresponds to IFT_ETHER */ + xreq.xarp_ha.sdl_type = 6; + xreq.xarp_ha.sdl_alen = ETHER_ADDR_LEN; + memcpy(xreq.xarp_ha.sdl_data + ifnamsz, mess->chaddr, mess->hlen); + xreq.xarp_flags = ATF_COM; + ioctl(daemon->dhcpfd, SIOCSXARP, &xreq); } #elif defined(HAVE_BSD_NETWORK) else