2 * dhcp.c DHCP processing.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2008 The FreeRADIUS server project
21 * Copyright 2008,2011 Alan DeKok <aland@deployingradius.com>
26 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
27 * CLIENT_IP : 68 <- DHCP_SERVER_IP : 67 OFFER
28 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
29 * CLIENT_IP : 68 <- DHCP_SERVER_IP : 67 ACK
32 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
33 * RELAY_IP : 67 -> NEXT_SERVER_IP : 67 DISCOVER
34 * (NEXT_SERVER_IP can be a relay itself)
35 * FIRST_RELAY_IP : 67 <- DHCP_SERVER_IP : 67 OFFER
36 * CLIENT_IP : 68 <- FIRST_RELAY_IP : 67 OFFER
37 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
38 * RELAY_IP : 67 -> NEXT_SERVER_IP : 67 REQUEST
39 * (NEXT_SERVER_IP can be a relay itself)
40 * FIRST_RELAY_IP : 67 <- DHCP_SERVER_IP : 67 ACK
41 * CLIENT_IP : 68 <- FIRST_RELAY_IP : 67 ACK
43 * Note: NACK are broadcasted, rest is unicast, unless client asked
48 #include <freeradius-devel/radiusd.h>
49 #include <freeradius-devel/modules.h>
50 #include <freeradius-devel/protocol.h>
51 #include <freeradius-devel/process.h>
52 #include <freeradius-devel/dhcp.h>
53 #include <freeradius-devel/rad_assert.h>
56 #include <sys/ioctl.h>
59 extern bool check_config; /* @todo globals are bad, m'kay? */
62 * Same contents as listen_socket_t.
64 typedef struct dhcp_socket_t {
65 listen_socket_t lsock;
68 * DHCP-specific additions.
70 bool suppress_responses;
71 RADCLIENT dhcp_client;
72 char const *src_interface;
73 fr_ipaddr_t src_ipaddr;
77 static int dhcprelay_process_client_request(REQUEST *request)
80 VALUE_PAIR *vp, *giaddr;
83 rad_assert(request->packet->data[0] == 1);
86 * Do the forward by ourselves, do not rely on dhcp_socket_send()
88 request->reply->code = 0;
91 * It's invalid to have giaddr=0 AND a relay option
93 giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
94 if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY)) &&
95 pairfind(request->packet->vps, 82, DHCP_MAGIC_VENDOR, TAG_ANY)) { /* DHCP-Relay-Agent-Information */
96 DEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet\n");
101 * RFC 1542 (BOOTP), page 15
103 * Drop requests if hop-count > 16 or admin specified another value
105 if ((vp = pairfind(request->config_items, 271, DHCP_MAGIC_VENDOR, TAG_ANY))) { /* DHCP-Relay-Max-Hop-Count */
106 maxhops = vp->vp_integer;
108 vp = pairfind(request->packet->vps, 259, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Hop-Count */
109 rad_assert(vp != NULL);
110 if (vp->vp_integer > maxhops) {
111 DEBUG("DHCP: Number of hops is greater than %d: not relaying\n", maxhops);
114 /* Increment hop count */
118 sock = request->listener->data;
121 * Forward the request to the next server using the
122 * incoming request as a template.
124 /* set SRC ipaddr/port to the listener ipaddr/port */
125 request->packet->src_ipaddr.af = AF_INET;
126 request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = sock->lsock.my_ipaddr.ipaddr.ip4addr.s_addr;
127 request->packet->src_port = sock->lsock.my_port;
129 vp = pairfind(request->config_items, 270, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-To-IP-Address */
130 rad_assert(vp != NULL);
132 /* set DEST ipaddr/port to the next server ipaddr/port */
133 request->packet->dst_ipaddr.af = AF_INET;
134 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
135 request->packet->dst_port = sock->lsock.my_port;
137 if (fr_dhcp_encode(request->packet) < 0) {
138 DEBUG("dhcprelay_process_client_request: ERROR in fr_dhcp_encode\n");
142 return fr_dhcp_send(request->packet);
147 * We've seen a reply from a server.
148 * i.e. we're a relay.
150 static int dhcprelay_process_server_reply(REQUEST *request)
152 VALUE_PAIR *vp, *giaddr;
155 rad_assert(request->packet->data[0] == 2);
158 * Do the forward by ourselves, do not rely on dhcp_socket_send()
160 request->reply->code = 0;
162 sock = request->listener->data;
165 * Check that packet is for us.
167 giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
169 /* --with-udpfromto is needed just for the following test */
170 if (!giaddr || giaddr->vp_ipaddr != request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr) {
171 DEBUG("DHCP: Packet received from server was not for us (was for 0x%x). Discarding packet",
172 ntohl(request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr));
176 /* set SRC ipaddr/port to the listener ipaddr/port */
177 request->packet->src_ipaddr.af = AF_INET;
178 request->packet->src_port = sock->lsock.my_port;
180 /* set DEST ipaddr/port to clientip/68 or broadcast in specific cases */
181 request->packet->dst_ipaddr.af = AF_INET;
184 * We're a relay, and send the reply to giaddr.
186 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = giaddr->vp_ipaddr;
187 request->reply->dst_port = request->packet->dst_port; /* server port */
189 if ((request->packet->code == PW_DHCP_NAK) ||
190 !sock->src_interface ||
191 ((vp = pairfind(request->packet->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Flags */ &&
192 (vp->vp_integer & 0x8000) &&
193 ((vp = pairfind(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
194 (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
201 * - Broadcast flag is set up and ciaddr == NULL
203 RDEBUG("DHCP: response will be broadcast");
204 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
210 * - ciaddr if present
211 * otherwise to yiaddr
213 if ((vp = pairfind(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
214 (vp->vp_ipaddr != htonl(INADDR_ANY))) {
215 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
217 vp = pairfind(request->packet->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
219 DEBUG("DHCP: Failed to find IP Address for request.");
223 RDEBUG("DHCP: response will be unicast to your-ip-address");
224 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
227 * When sending a DHCP_OFFER, make sure our ARP table
228 * contains an entry for the client IP address, or else
229 * packet may not be forwarded if it was the first time
230 * the client was requesting an IP address.
232 if (request->packet->code == PW_DHCP_OFFER) {
233 VALUE_PAIR *hwvp = pairfind(request->packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
235 DEBUG("DHCP: DHCP_OFFER packet received with "
236 "no Client Hardware Address. Discarding packet");
239 if (fr_dhcp_add_arp_entry(request->packet->sockfd, sock->src_interface, hwvp, vp) < 0) {
240 DEBUG("%s", fr_strerror());
247 if (fr_dhcp_encode(request->packet) < 0) {
248 DEBUG("dhcprelay_process_server_reply: ERROR in fr_dhcp_encode\n");
252 return fr_dhcp_send(request->packet);
254 #else /* WITH_UDPFROMTO */
255 static int dhcprelay_process_server_reply(UNUSED REQUEST *request)
257 WDEBUG("DHCP Relaying requires the server to be configured with UDPFROMTO");
261 static int dhcprelay_process_client_request(UNUSED REQUEST *request)
263 WDEBUG("DHCP Relaying requires the server to be configured with UDPFROMTO");
267 #endif /* WITH_UDPFROMTO */
269 static const uint32_t attrnums[] = {
270 57, /* DHCP-DHCP-Maximum-Msg-Size */
271 256, /* DHCP-Opcode */
272 257, /* DHCP-Hardware-Type */
273 258, /* DHCP-Hardware-Address-Length */
274 259, /* DHCP-Hop-Count */
275 260, /* DHCP-Transaction-Id */
276 262, /* DHCP-Flags */
277 263, /* DHCP-Client-IP-Address */
278 266, /* DHCP-Gateway-IP-Address */
279 267 /* DHCP-Client-Hardware-Address */
282 static int dhcp_process(REQUEST *request)
290 * If there's a giaddr, save it as the Relay-IP-Address
291 * in the response. That way the later code knows where
294 vp = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
295 if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
298 /* DHCP-Relay-IP-Address */
299 relay = radius_paircreate(request->reply, &request->reply->vps,
300 272, DHCP_MAGIC_VENDOR);
301 if (relay) relay->vp_ipaddr = vp->vp_ipaddr;
304 vp = pairfind(request->packet->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */
306 DICT_VALUE *dv = dict_valbyattr(53, DHCP_MAGIC_VENDOR, vp->vp_integer);
307 DEBUG("Trying sub-section dhcp %s {...}",
308 dv->name ? dv->name : "<unknown>");
309 rcode = process_post_auth(vp->vp_integer, request);
311 DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!");
312 rcode = RLM_MODULE_FAIL;
315 vp = pairfind(request->reply->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */
317 request->reply->code = vp->vp_integer;
318 if ((request->reply->code != 0) &&
319 (request->reply->code < PW_DHCP_OFFSET)) {
320 request->reply->code += PW_DHCP_OFFSET;
323 else switch (rcode) {
325 case RLM_MODULE_UPDATED:
326 if (request->packet->code == PW_DHCP_DISCOVER) {
327 request->reply->code = PW_DHCP_OFFER;
330 } else if (request->packet->code == PW_DHCP_REQUEST) {
331 request->reply->code = PW_DHCP_ACK;
334 request->reply->code = PW_DHCP_NAK;
338 case RLM_MODULE_REJECT:
339 case RLM_MODULE_FAIL:
340 case RLM_MODULE_INVALID:
341 case RLM_MODULE_NOOP:
342 case RLM_MODULE_NOTFOUND:
343 if (request->packet->code == PW_DHCP_DISCOVER) {
344 request->reply->code = 0; /* ignore the packet */
346 request->reply->code = PW_DHCP_NAK;
350 case RLM_MODULE_HANDLED:
351 request->reply->code = 0; /* ignore the packet */
356 * TODO: Handle 'output' of RLM_MODULE when acting as a
357 * DHCP relay We may want to not forward packets in
358 * certain circumstances.
362 * Handle requests when acting as a DHCP relay
364 vp = pairfind(request->packet->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */
366 RDEBUG("FAILURE: Someone deleted the DHCP-Opcode!");
370 /* BOOTREPLY received on port 67 (i.e. from a server) */
371 if (vp->vp_integer == 2) {
372 return dhcprelay_process_server_reply(request);
375 /* Packet from client, and we have DHCP-Relay-To-IP-Address */
376 if (pairfind(request->config_items, 270, DHCP_MAGIC_VENDOR, TAG_ANY)) {
377 return dhcprelay_process_client_request(request);
380 /* else it's a packet from a client, without relaying */
381 rad_assert(vp->vp_integer == 1); /* BOOTREQUEST */
383 sock = request->listener->data;
386 * Handle requests when acting as a DHCP server
390 * Releases don't get replies.
392 if (request->packet->code == PW_DHCP_RELEASE) {
393 request->reply->code = 0;
396 if (request->reply->code == 0) {
400 request->reply->sockfd = request->packet->sockfd;
403 * Copy specific fields from packet to reply, if they
404 * don't already exist
406 for (i = 0; i < sizeof(attrnums) / sizeof(attrnums[0]); i++) {
407 uint32_t attr = attrnums[i];
409 if (pairfind(request->reply->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY)) continue;
411 vp = pairfind(request->packet->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY);
413 pairadd(&request->reply->vps, paircopyvp(request->reply, vp));
417 vp = pairfind(request->reply->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */
418 rad_assert(vp != NULL);
419 vp->vp_integer = 2; /* BOOTREPLY */
422 * Allow NAKs to be delayed for a short period of time.
424 if (request->reply->code == PW_DHCP_NAK) {
425 vp = pairfind(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY, 0, TAG_ANY);
427 if (vp->vp_integer <= 10) {
428 request->response_delay = vp->vp_integer;
430 request->response_delay = 10;
436 * Prepare the reply packet for sending through dhcp_socket_send()
438 request->reply->dst_ipaddr.af = AF_INET;
439 request->reply->src_ipaddr.af = AF_INET;
440 request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = sock->src_ipaddr.ipaddr.ip4addr.s_addr;
443 * They didn't set a proper src_ipaddr, but we want to
444 * send the packet with a source IP. If there's a server
445 * identifier, use it.
447 if (request->reply->src_ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY) {
448 vp = pairfind(request->reply->vps, 265, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Server-IP-Address */
449 if (!vp) vp = pairfind(request->reply->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-DHCP-Server-Identifier */
451 request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
455 request->reply->dst_port = request->packet->src_port;
456 request->reply->src_port = request->packet->dst_port;
459 * Answer to client's nearest DHCP relay.
461 * Which may be different than the giaddr given in the
462 * packet to the client. i.e. the relay may have a
463 * public IP, but the gateway a private one.
465 vp = pairfind(request->reply->vps, 272, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-IP-Address */
466 if (vp && (vp->vp_ipaddr != ntohl(INADDR_ANY))) {
467 RDEBUG("DHCP: Reply will be unicast to giaddr from original packet");
468 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
473 * Answer to client's nearest DHCP gateway. In this
474 * case, the client can reach the gateway, as can the
477 * We also use *our* source port as the destination port.
478 * Gateways are servers, and listen on the server port,
479 * not the client port.
481 vp = pairfind(request->reply->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
482 if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
483 RDEBUG("DHCP: Reply will be unicast to giaddr");
484 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
485 request->reply->dst_port = request->packet->dst_port;
490 * If it's a NAK, or the broadcast flag was set, ond
491 * there's no client-ip-address, send a broadcast.
493 if ((request->reply->code == PW_DHCP_NAK) ||
494 ((vp = pairfind(request->reply->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Flags */
495 (vp->vp_integer & 0x8000) &&
496 ((vp = pairfind(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */
497 (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
504 * - Broadcast flag is set up and ciaddr == NULL
506 RDEBUG("DHCP: Reply will be broadcast");
507 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
514 * Unicast to ciaddr if present, otherwise to yiaddr.
516 if ((vp = pairfind(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */
517 (vp->vp_ipaddr != htonl(INADDR_ANY))) {
518 RDEBUG("DHCP: Reply will be sent unicast to client-ip-address");
519 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
523 vp = pairfind(request->reply->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
525 RDEBUG("DHCP: Failed to find DHCP-Client-IP-Address or DHCP-Your-IP-Address for request; "
528 * There is nowhere to send the response to, so don't bother.
530 request->reply->code = 0;
536 * The system is configured to listen for broadcast
537 * packets, which means we'll need to send unicast
538 * replies, to IPs which haven't yet been assigned.
539 * Therefore, we need to update the ARP table.
541 * However, they haven't specified a interface. So we
542 * can't update the ARP table. And we must send a
543 * broadcast response.
545 if (sock->lsock.broadcast && !sock->src_interface) {
546 WARN("You MUST set \"interface\" if you have \"broadcast = yes\"");
547 RDEBUG("DHCP: Reply will be broadcast as no interface was defined");
548 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
552 RDEBUG("DHCP: Reply will be unicast to your-ip-address");
553 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
556 * When sending a DHCP_OFFER, make sure our ARP table
557 * contains an entry for the client IP address.
558 * Otherwise the packet may not be sent to the client, as
559 * the OS has no ARP entry for it.
561 * This is a cute hack to avoid us having to create a raw
562 * socket to send DHCP packets.
564 if (request->reply->code == PW_DHCP_OFFER) {
565 VALUE_PAIR *hwvp = pairfind(request->reply->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
567 if (!hwvp) return -1;
569 if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) {
570 RDEBUG("Failed adding arp entry: %s", fr_strerror());
575 if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr != ntohl(INADDR_NONE)) {
576 RDEBUG("DHCP: Request will be unicast to the unicast source IP address");
577 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
579 RDEBUG("DHCP: Reply will be broadcast as this system does not support ARP updates");
580 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
587 static int dhcp_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
589 int rcode, broadcast = 1;
595 rcode = common_socket_parse(cs, this);
596 if (rcode != 0) return rcode;
598 if (check_config) return 0;
602 if (!sock->lsock.interface) {
603 WDEBUG("No \"interface\" setting is defined. Only unicast DHCP will work.");
607 * See whether or not we enable broadcast packets.
609 cp = cf_pair_find(cs, "broadcast");
611 char const *value = cf_pair_value(cp);
612 if (value && (strcmp(value, "no") == 0)) {
618 if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
619 ERROR("Can't set broadcast option: %s\n",
625 if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
626 ERROR("Can't set re-use addres option: %s\n",
632 * Undocumented extension for testing without
633 * destroying your network!
635 sock->suppress_responses = false;
636 cp = cf_pair_find(cs, "suppress_responses");
638 cf_item_parse(cs, "suppress_responses", PW_TYPE_BOOLEAN,
639 &sock->suppress_responses, NULL);
642 cp = cf_pair_find(cs, "src_interface");
644 cf_item_parse(cs, "src_interface", PW_TYPE_STRING_PTR,
645 &sock->src_interface, NULL);
647 sock->src_interface = sock->lsock.interface;
650 if (!sock->src_interface && sock->lsock.interface) {
651 sock->src_interface = talloc_typed_strdup(sock, sock->lsock.interface);
654 cp = cf_pair_find(cs, "src_ipaddr");
656 memset(&sock->src_ipaddr, 0, sizeof(sock->src_ipaddr));
657 sock->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
658 rcode = cf_item_parse(cs, "src_ipaddr", PW_TYPE_IPADDR,
659 &sock->src_ipaddr.ipaddr.ip4addr, NULL);
660 if (rcode < 0) return -1;
662 sock->src_ipaddr.af = AF_INET;
664 memcpy(&sock->src_ipaddr, &sock->lsock.my_ipaddr, sizeof(sock->src_ipaddr));
668 * Initialize the fake client.
670 client = &sock->dhcp_client;
671 memset(client, 0, sizeof(*client));
672 client->ipaddr.af = AF_INET;
673 client->ipaddr.ipaddr.ip4addr.s_addr = ntohl(INADDR_NONE);
675 client->longname = client->shortname = "dhcp";
676 client->secret = client->shortname;
677 client->nas_type = talloc_typed_strdup(sock, "none");
684 * Check if an incoming request is "ok"
686 * It takes packets, not requests. It sees if the packet looks
687 * OK. If so, it does a number of sanity checks on it.
689 static int dhcp_socket_recv(rad_listen_t *listener)
691 RADIUS_PACKET *packet;
694 packet = fr_dhcp_recv(listener->fd);
696 ERROR("%s", fr_strerror());
700 sock = listener->data;
701 if (!request_receive(listener, packet, &sock->dhcp_client, dhcp_process)) {
711 * Send an authentication response packet
713 static int dhcp_socket_send(rad_listen_t *listener, REQUEST *request)
717 rad_assert(request->listener == listener);
718 rad_assert(listener->send == dhcp_socket_send);
720 if (request->reply->code == 0) return 0; /* don't reply */
722 if (fr_dhcp_encode(request->reply) < 0) {
723 DEBUG("dhcp_socket_send: ERROR\n");
727 sock = listener->data;
728 if (sock->suppress_responses) return 0;
730 return fr_dhcp_send(request->reply);
734 static int dhcp_socket_encode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
736 DEBUG2("NO ENCODE!");
741 static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
743 return fr_dhcp_decode(request->packet);
746 fr_protocol_t proto_dhcp = {
749 sizeof(dhcp_socket_t),
751 dhcp_socket_parse, NULL,
752 dhcp_socket_recv, dhcp_socket_send,
753 common_socket_print, dhcp_socket_encode, dhcp_socket_decode