From: Alan T. DeKok Date: Thu, 10 Feb 2011 09:49:03 +0000 (+0100) Subject: Change the rules for sending DHCP responses X-Git-Tag: release_2_1_11~131 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=667aaae471805a3be53be15a3cde866b9382a6d5;p=thirdparty%2Ffreeradius-server.git Change the rules for sending DHCP responses giaddr -> giaddr broadcast -> broadcast nak -> broadcast !ciaddr -> broadcast ciaddr -> ciaddr BUT if the request was not *from* ciaddr, we need to send a "raw" response. Many DHCP clients can handle a broadcast DHCP OFFER / ACK when first assigning an address. Some clients expect a response unicast to their MAC address. --- diff --git a/src/lib/dhcp.c b/src/lib/dhcp.c index 603c07fb6ba..105db0eb326 100644 --- a/src/lib/dhcp.c +++ b/src/lib/dhcp.c @@ -375,6 +375,17 @@ int fr_dhcp_send(RADIUS_PACKET *packet) fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port, &dst, &sizeof_dst); + /* + * The client doesn't yet have an IP address, but is + * expecting an ethernet packet unicast to it's MAC + * address. We need to build a raw frame. + */ + if (packet->offset == 0) { + /* + * FIXME: Insert code here! + */ + } + #ifndef WITH_UDPFROMTO /* * Assume that the packet is encoded before sending it. @@ -978,11 +989,10 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original) * to the client. * * if giaddr, send to giaddr. - * if NAK, send broadcast packet - * if ciaddr, unicast to ciaddr - * if flags & 0x8000, broadcast (client request) - * if sent from 0.0.0.0, broadcast response - * unicast to client yiaddr + * if NAK, send broadcast. + * if broadcast flag, send broadcast. + * if ciaddr is empty, send broadcast. + * otherwise unicast to ciaddr. */ /* @@ -991,6 +1001,12 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original) */ dhcp = (dhcp_packet_t *) original->data; + /* + * Default to sending it via sendto(), without using + * raw sockets. + */ + packet->offset = 1; + if (dhcp->giaddr != htonl(INADDR_ANY)) { packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->giaddr; @@ -1000,23 +1016,24 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original) packet->dst_port = original->src_port; /* debugging */ } - } else if (packet->code == PW_DHCP_NAK) { - packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST); - - } else if (dhcp->ciaddr != htonl(INADDR_ANY)) { - packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->ciaddr; - - } else if ((dhcp->flags & 0x8000) != 0) { - packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST); - - } else if (packet->dst_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY)) { + } else if ((packet->code == PW_DHCP_NAK) || + ((dhcp->flags & 0x8000) != 0) || + (dhcp->ciaddr == htonl(INADDR_ANY))) { + /* + * The kernel will take care of sending it to + * the broadcast MAC. + */ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST); - } else if (dhcp->yiaddr != htonl(INADDR_ANY)) { - packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->yiaddr; - } else { - /* leave destination IP alone. */ + /* + * It was broadcast to us: we need to + * broadcast the response. + */ + if (packet->src_ipaddr.ipaddr.ip4addr.s_addr != dhcp->ciaddr) { + packet->offset = 0; + } + packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->ciaddr; } /*