FR-GV-203 - fix memory leak when using decode_tlv()
[freeradius.git] / src / lib / dhcp.c
1 /*
2  * dhcp.c       Functions to send/receive dhcp packets.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library 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 GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2008 The FreeRADIUS server project
21  * Copyright 2008 Alan DeKok <aland@deployingradius.com>
22  */
23
24 #include        <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/libradius.h>
28 #include <freeradius-devel/udpfromto.h>
29 #include <freeradius-devel/dhcp.h>
30
31 #ifdef WITH_DHCP
32
33 #include <sys/ioctl.h>
34
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38 #ifdef HAVE_SYS_TYPES_H
39 #include <sys/types.h>
40 #endif
41
42 #include <net/if_arp.h>
43
44
45 #define DHCP_CHADDR_LEN (16)
46 #define DHCP_SNAME_LEN  (64)
47 #define DHCP_FILE_LEN   (128)
48 #define DHCP_VEND_LEN   (308)
49 #define DHCP_OPTION_MAGIC_NUMBER (0x63825363)
50
51 #ifndef INADDR_BROADCAST
52 #define INADDR_BROADCAST INADDR_NONE
53 #endif
54
55 typedef struct dhcp_packet_t {
56         uint8_t         opcode;
57         uint8_t         htype;
58         uint8_t         hlen;
59         uint8_t         hops;
60         uint32_t        xid;    /* 4 */
61         uint16_t        secs;   /* 8 */
62         uint16_t        flags;
63         uint32_t        ciaddr; /* 12 */
64         uint32_t        yiaddr; /* 16 */
65         uint32_t        siaddr; /* 20 */
66         uint32_t        giaddr; /* 24 */
67         uint8_t         chaddr[DHCP_CHADDR_LEN]; /* 28 */
68         uint8_t         sname[DHCP_SNAME_LEN]; /* 44 */
69         uint8_t         file[DHCP_FILE_LEN]; /* 108 */
70         uint32_t        option_format; /* 236 */
71         uint8_t         options[DHCP_VEND_LEN];
72 } dhcp_packet_t;
73
74 typedef struct dhcp_option_t {
75         uint8_t         code;
76         uint8_t         length;
77 } dhcp_option_t;
78
79 /*
80  *      INADDR_ANY : 68 -> INADDR_BROADCAST : 67        DISCOVER
81  *      INADDR_BROADCAST : 68 <- SERVER_IP : 67         OFFER
82  *      INADDR_ANY : 68 -> INADDR_BROADCAST : 67        REQUEST
83  *      INADDR_BROADCAST : 68 <- SERVER_IP : 67         ACK
84  */
85 static const char *dhcp_header_names[] = {
86         "DHCP-Opcode",
87         "DHCP-Hardware-Type",
88         "DHCP-Hardware-Address-Length",
89         "DHCP-Hop-Count",
90         "DHCP-Transaction-Id",
91         "DHCP-Number-of-Seconds",
92         "DHCP-Flags",
93         "DHCP-Client-IP-Address",
94         "DHCP-Your-IP-Address",
95         "DHCP-Server-IP-Address",
96         "DHCP-Gateway-IP-Address",
97         "DHCP-Client-Hardware-Address",
98         "DHCP-Server-Host-Name",
99         "DHCP-Boot-Filename",
100
101         NULL
102 };
103
104 static const char *dhcp_message_types[] = {
105         "invalid",
106         "DHCP-Discover",
107         "DHCP-Offer",
108         "DHCP-Request",
109         "DHCP-Decline",
110         "DHCP-Ack",
111         "DHCP-NAK",
112         "DHCP-Release",
113         "DHCP-Inform",
114         "DHCP-Force-Renew",
115 };
116
117 static int dhcp_header_sizes[] = {
118         1, 1, 1, 1,
119         4, 2, 2, 4,
120         4, 4, 4,
121         DHCP_CHADDR_LEN,
122         DHCP_SNAME_LEN,
123         DHCP_FILE_LEN
124 };
125
126
127 /*
128  *      Some clients silently ignore responses less than 300 bytes.
129  */
130 #define MIN_PACKET_SIZE (244)
131 #define DEFAULT_PACKET_SIZE (300)
132 #define MAX_PACKET_SIZE (1500 - 40)
133
134 #define DHCP_OPTION_FIELD (0)
135 #define DHCP_FILE_FIELD   (1)
136 #define DHCP_SNAME_FIELD  (2)
137
138 static uint8_t *dhcp_get_option(dhcp_packet_t *packet, size_t packet_size,
139                                 unsigned int option)
140 {
141         int overload = 0;
142         int field = DHCP_OPTION_FIELD;
143         size_t where, size;
144         uint8_t *data;
145
146         where = 0;
147         size = packet_size - offsetof(dhcp_packet_t, options);
148         data = &packet->options[where];
149
150         while (where < size) {
151                 if (data[0] == 0) { /* padding */
152                         where++;
153                         continue;
154                 }
155
156                 if (data[0] == 255) { /* end of options */
157                         if ((field == DHCP_OPTION_FIELD) &&
158                             (overload & DHCP_FILE_FIELD)) {
159                                 data = packet->file;
160                                 where = 0;
161                                 size = sizeof(packet->file);
162                                 field = DHCP_FILE_FIELD;
163                                 continue;
164
165                         } else if ((field == DHCP_FILE_FIELD) &&
166                                    (overload & DHCP_SNAME_FIELD)) {
167                                 data = packet->sname;
168                                 where = 0;
169                                 size = sizeof(packet->sname);
170                                 field = DHCP_SNAME_FIELD;
171                                 continue;
172                         }
173
174                         return NULL;
175                 }
176
177                 /*
178                  *      We MUST have a real option here.
179                  */
180                 if ((where + 2) > size) {
181                         fr_strerror_printf("Options overflow field at %u",
182                                            (unsigned int) (data - (uint8_t *) packet));
183                         return NULL;
184                 }
185
186                 if ((where + 2 + data[1]) > size) {
187                         fr_strerror_printf("Option length overflows field at %u",
188                                            (unsigned int) (data - (uint8_t *) packet));
189                         return NULL;
190                 }
191
192                 if (data[0] == option) return data;
193
194                 if (data[0] == 52) { /* overload sname and/or file */
195                         overload = data[3];
196                 }
197
198                 where += data[1] + 2;
199                 data += data[1] + 2;
200         }
201
202         return NULL;
203 }
204
205 /*
206  *      DHCPv4 is only for IPv4.  Broadcast only works if udpfromto is
207  *      defined.
208  */
209 RADIUS_PACKET *fr_dhcp_recv(int sockfd)
210 {
211         uint32_t                magic;
212         struct sockaddr_storage src;
213         struct sockaddr_storage dst;
214         socklen_t               sizeof_src;
215         socklen_t               sizeof_dst;
216         RADIUS_PACKET           *packet;
217         int                     port;
218         uint8_t                 *code;
219         ssize_t                 data_len;
220
221         packet = rad_alloc(0);
222         if (!packet) {
223                 fr_strerror_printf("Failed allocating packet");
224                 return NULL;
225         }
226         memset(packet, 0, sizeof(*packet));
227
228         packet->data = malloc(MAX_PACKET_SIZE);
229         if (!packet->data) {
230                 fr_strerror_printf("Failed in malloc");
231                 rad_free(&packet);
232                 return NULL;
233         }
234
235         packet->sockfd = sockfd;
236         sizeof_src = sizeof(src);
237 #ifdef WITH_UDPFROMTO
238         sizeof_dst = sizeof(dst);
239         data_len = recvfromto(sockfd, packet->data, MAX_PACKET_SIZE, 0,
240                               (struct sockaddr *)&src, &sizeof_src,
241                               (struct sockaddr *)&dst, &sizeof_dst);
242 #else
243         data_len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,
244                             (struct sockaddr *)&src, &sizeof_src);
245 #endif
246
247         if (data_len <= 0) {
248                 fr_strerror_printf("Failed reading DHCP socket: %s", strerror(errno));
249                 rad_free(&packet);
250                 return NULL;
251         }
252
253         packet->data_len = data_len;
254         if (packet->data_len < MIN_PACKET_SIZE) {
255                 fr_strerror_printf("DHCP packet is too small (%d < %d)",
256                                    packet->data_len, MIN_PACKET_SIZE);
257                 rad_free(&packet);
258                 return NULL;
259         }
260
261         if (packet->data[1] != 1) {
262                 fr_strerror_printf("DHCP can only receive ethernet requests, not type %02x",
263                       packet->data[1]);
264                 rad_free(&packet);
265                 return NULL;
266         }
267
268         if (packet->data[2] != 6) {
269                 fr_strerror_printf("Ethernet HW length is wrong length %d",
270                         packet->data[2]);
271                 rad_free(&packet);
272                 return NULL;
273         }
274
275         memcpy(&magic, packet->data + 236, 4);
276         magic = ntohl(magic);
277         if (magic != DHCP_OPTION_MAGIC_NUMBER) {
278                 fr_strerror_printf("Cannot do BOOTP");
279                 rad_free(&packet);
280                 return NULL;
281         }
282
283         /*
284          *      Create unique keys for the packet.
285          */
286         memcpy(&magic, packet->data + 4, 4);
287         packet->id = ntohl(magic);
288
289         code = dhcp_get_option((dhcp_packet_t *) packet->data,
290                                packet->data_len, 53);
291         if (!code) {
292                 fr_strerror_printf("No message-type option was found in the packet");
293                 rad_free(&packet);
294                 return NULL;
295         }
296
297         if ((code[1] < 1) || (code[2] == 0) || (code[2] > 8)) {
298                 fr_strerror_printf("Unknown value for message-type option");
299                 rad_free(&packet);
300                 return NULL;
301         }
302
303         packet->code = code[2] | PW_DHCP_OFFSET;
304
305         /*
306          *      Create a unique vector from the MAC address and the
307          *      DHCP opcode.  This is a hack for the RADIUS
308          *      infrastructure in the rest of the server.
309          *
310          *      Note: packet->data[2] == 6, which is smaller than
311          *      sizeof(packet->vector)
312          *
313          *      FIXME:  Look for client-identifier in packet,
314          *      and use that, too?
315          */
316         memset(packet->vector, 0, sizeof(packet->vector));
317         memcpy(packet->vector, packet->data + 28, packet->data[2]);
318         packet->vector[packet->data[2]] = packet->code & 0xff;
319
320         /*
321          *      FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1
322          *      FIXME: for OFFER / ACK       : src_port = dst_port - 1
323          */
324
325         /*
326          *      Unique keys are xid, client mac, and client ID?
327          */
328
329         /*
330          *      FIXME: More checks, like DHCP packet type?
331          */
332
333         sizeof_dst = sizeof(dst);
334
335 #ifndef WITH_UDPFROMTO
336         /*
337          *      This should never fail...
338          */
339         if (getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst) < 0) {
340                 fr_strerror_printf("getsockname failed: %s", strerror(errno));
341                 rad_free(&packet);
342                 return NULL;
343         }
344 #endif
345
346         fr_sockaddr2ipaddr(&dst, sizeof_dst, &packet->dst_ipaddr, &port);
347         packet->dst_port = port;
348
349         fr_sockaddr2ipaddr(&src, sizeof_src, &packet->src_ipaddr, &port);
350         packet->src_port = port;
351
352         if (fr_debug_flag > 1) {
353                 char type_buf[64];
354                 const char *name = type_buf;
355                 char src_ip_buf[256], dst_ip_buf[256];
356
357                 if ((packet->code >= PW_DHCP_DISCOVER) &&
358                     (packet->code <= PW_DHCP_INFORM)) {
359                         name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
360                 } else {
361                         snprintf(type_buf, sizeof(type_buf), "%d",
362                                  packet->code - PW_DHCP_OFFSET);
363                 }
364
365                 DEBUG("Received %s of id %08x from %s:%d to %s:%d\n",
366                        name, (unsigned int) packet->id,
367                        inet_ntop(packet->src_ipaddr.af,
368                                  &packet->src_ipaddr.ipaddr,
369                                  src_ip_buf, sizeof(src_ip_buf)),
370                        packet->src_port,
371                        inet_ntop(packet->dst_ipaddr.af,
372                                  &packet->dst_ipaddr.ipaddr,
373                                  dst_ip_buf, sizeof(dst_ip_buf)),
374                        packet->dst_port);
375         }
376
377         return packet;
378 }
379
380
381 /*
382  *      Send a DHCP packet.
383  */
384 int fr_dhcp_send(RADIUS_PACKET *packet)
385 {
386         struct sockaddr_storage dst;
387         socklen_t               sizeof_dst;
388 #ifdef WITH_UDPFROMTO
389         struct sockaddr_storage src;
390         socklen_t               sizeof_src;
391
392         fr_ipaddr2sockaddr(&packet->src_ipaddr, packet->src_port,
393             &src, &sizeof_src);
394 #endif
395
396         fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port,
397                            &dst, &sizeof_dst);
398
399         if (fr_debug_flag > 1) {
400                 char type_buf[64];
401                 const char *name = type_buf;
402 #ifdef WITH_UDPFROMTO
403                 char src_ip_buf[256];
404 #endif
405                 char dst_ip_buf[256];
406
407                 if ((packet->code >= PW_DHCP_DISCOVER) &&
408                     (packet->code <= PW_DHCP_INFORM)) {
409                         name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
410                 } else {
411                         snprintf(type_buf, sizeof(type_buf), "%d",
412                             packet->code - PW_DHCP_OFFSET);
413                 }
414
415                 DEBUG(
416 #ifdef WITH_UDPFROMTO
417                 "Sending %s of id %08x from %s:%d to %s:%d\n",
418 #else
419                 "Sending %s of id %08x to %s:%d\n",
420 #endif
421                    name, (unsigned int) packet->id,
422 #ifdef WITH_UDPFROMTO
423                    inet_ntop(packet->src_ipaddr.af,
424                      &packet->src_ipaddr.ipaddr,
425                      src_ip_buf, sizeof(src_ip_buf)),
426                    packet->src_port,
427 #endif
428                    inet_ntop(packet->dst_ipaddr.af,
429                      &packet->dst_ipaddr.ipaddr,
430                      dst_ip_buf, sizeof(dst_ip_buf)),
431                    packet->dst_port);
432         }
433
434 #ifndef WITH_UDPFROMTO
435         /*
436          *      Assume that the packet is encoded before sending it.
437          */
438         return sendto(packet->sockfd, packet->data, packet->data_len, 0,
439                       (struct sockaddr *)&dst, sizeof_dst);
440 #else
441
442         return sendfromto(packet->sockfd, packet->data, packet->data_len, 0,
443                           (struct sockaddr *)&src, sizeof_src,
444                           (struct sockaddr *)&dst, sizeof_dst);
445 #endif
446 }
447
448 static int fr_dhcp_attr2vp(VALUE_PAIR *vp, const uint8_t *p, size_t alen);
449
450 static int decode_tlv(VALUE_PAIR *tlv, const uint8_t *data, size_t data_len)
451 {
452         const uint8_t *p;
453         VALUE_PAIR *head, **tail, *vp;
454
455         /*
456          *      Take a pass at parsing it.
457          */
458         p = data;
459         while (p < (data + data_len)) {
460                 if ((p + 2) > (data + data_len)) goto make_tlv;
461
462                 if ((p + p[1] + 2) > (data + data_len)) goto make_tlv;
463                 p += 2 + p[1];
464         }
465
466         /*
467          *      Got here... must be well formed.
468          */
469         head = NULL;
470         tail = &head;
471
472         p = data;
473         while (p < (data + data_len)) {
474                 vp = paircreate(tlv->attribute | (p[0] << 8), PW_TYPE_OCTETS);
475                 if (!vp) {
476                         pairfree(&head);
477                         goto make_tlv;
478                 }
479
480                 if (fr_dhcp_attr2vp(vp, p + 2, p[1]) < 0) {
481                         pairfree(&vp);
482                         pairfree(&head);
483                         goto make_tlv;
484                 }
485
486                 *tail = vp;
487                 while (*tail) tail = &((*tail)->next);
488                 p += 2 + p[1];
489         }
490
491         /*
492          *      The caller allocated TLV, so we need to copy the FIRST
493          *      attribute over top of that.
494          */
495         if (head) {
496                 memcpy(tlv, head, sizeof(*tlv));
497                 head->next = NULL;
498                 if (head->type == PW_TYPE_TLV) head->vp_tlv = NULL;
499                 pairfree(&head);
500         }
501
502         return 0;
503
504 make_tlv:
505         if (data_len > sizeof(tlv->vp_octets)) data_len = sizeof(tlv->vp_octets);
506         memcpy(tlv->vp_octets, data, data_len);
507         tlv->length = data_len;
508         tlv->type = PW_TYPE_OCTETS;
509
510         return 0;
511 }
512
513
514 /*
515  *      Decode ONE value into a VP
516  */
517 static int fr_dhcp_attr2vp(VALUE_PAIR *vp, const uint8_t *p, size_t alen)
518 {
519         switch (vp->type) {
520         case PW_TYPE_BYTE:
521                 if (alen != 1) goto raw;
522                 vp->vp_integer = p[0];
523                 break;
524
525         case PW_TYPE_SHORT:
526                 if (alen != 2) goto raw;
527                 memcpy(&vp->vp_integer, p, 2);
528                 vp->vp_integer = ntohs(vp->vp_integer);
529                 break;
530
531         case PW_TYPE_INTEGER:
532                 if (alen != 4) goto raw;
533                 memcpy(&vp->vp_integer, p, 4);
534                 vp->vp_integer = ntohl(vp->vp_integer);
535                 break;
536
537         case PW_TYPE_IPADDR:
538                 if (alen != 4) goto raw;
539                 /*
540                  *      Keep value in Network Order!
541                  */
542                 memcpy(&vp->vp_ipaddr, p , 4);
543                 vp->length = 4;
544                 break;
545
546         case PW_TYPE_STRING:
547                 if (alen > 253) return -1;
548                 memcpy(vp->vp_strvalue, p , alen);
549                 vp->vp_strvalue[alen] = '\0';
550                 break;
551
552         raw:
553                 vp->type = PW_TYPE_OCTETS;
554
555         case PW_TYPE_OCTETS:
556                 if (alen > 253) return -1;
557                 memcpy(vp->vp_octets, p, alen);
558                 break;
559
560         case PW_TYPE_TLV:
561                 return decode_tlv(vp, p, alen);
562
563         default:
564                 fr_strerror_printf("Internal sanity check %d %d", vp->type, __LINE__);
565                 return -1;
566         } /* switch over type */
567
568         vp->length = alen;
569         return 0;
570 }
571
572 ssize_t fr_dhcp_decode_options(uint8_t *data, size_t len, VALUE_PAIR **head)
573 {
574         int i;
575         VALUE_PAIR *vp, **tail;
576         uint8_t *p, *next;
577         next = data;
578
579         *head = NULL;
580         tail = head;
581         while (next < (data + len)) {
582                 int num_entries, alen;
583                 DICT_ATTR *da;
584
585                 p = next;
586
587                 if (*p == 0) {          /* 0x00 - Padding option */
588                         next++;
589                         continue;
590                 }
591                 if (*p == 255) break;   /* 0xff - End of options signifier */
592                 if ((p + 2) > (data + len)) break;
593
594                 next = p + 2 + p[1];
595
596                 if (p[1] >= 253) {
597                         fr_strerror_printf("Attribute too long %u %u",
598                                            p[0], p[1]);
599                         continue;
600                 }
601
602                 da = dict_attrbyvalue(DHCP2ATTR(p[0]));
603                 if (!da) {
604                         fr_strerror_printf("Attribute not in our dictionary: %u",
605                                            p[0]);
606                         continue;
607                 }
608
609                 vp = NULL;
610                 num_entries = 1;
611                 alen = p[1];
612                 p += 2;
613
614                 /*
615                  *      Could be an array of bytes, integers, etc.
616                  */
617                 if (da->flags.array) {
618                         switch (da->type) {
619                         case PW_TYPE_BYTE:
620                                 num_entries = alen;
621                                 alen = 1;
622                                 break;
623
624                         case PW_TYPE_SHORT: /* ignore any trailing data */
625                                 num_entries = alen >> 1;
626                                 alen = 2;
627                                 break;
628
629                         case PW_TYPE_IPADDR:
630                         case PW_TYPE_INTEGER:
631                         case PW_TYPE_DATE: /* ignore any trailing data */
632                                 num_entries = alen >> 2;
633                                 alen = 4;
634                                 break;
635
636                         default:
637
638                                 break; /* really an internal sanity failure */
639                         }
640                 }
641
642                 /*
643                  *      Loop over all of the entries, building VPs
644                  */
645                 for (i = 0; i < num_entries; i++) {
646                         vp = pairmake(da->name, NULL, T_OP_ADD);
647                         if (!vp) {
648                                 fr_strerror_printf("Cannot build attribute %s",
649                                         fr_strerror());
650                                 pairfree(head);
651                                 return -1;
652                         }
653
654                         /*
655                          *      Hack for ease of use.
656                          */
657                         if ((da->attr == DHCP2ATTR(0x3d)) &&
658                             !da->flags.array &&
659                             (alen == 7) && (*p == 1) && (num_entries == 1)) {
660                                 vp->type = PW_TYPE_ETHERNET;
661                                 memcpy(vp->vp_octets, p + 1, 6);
662                                 vp->length = alen;
663
664                         } else if (fr_dhcp_attr2vp(vp, p, alen) < 0) {
665                                 pairfree(&vp);
666                                 pairfree(head);
667                                 return -1;
668                         }
669
670                         *tail = vp;
671                         while (*tail) {
672                                 debug_pair(*tail);
673                                 tail = &(*tail)->next;
674                         }
675                         p += alen;
676                 } /* loop over array entries */
677         } /* loop over the entire packet */
678
679         return next - data;
680 }
681
682 int fr_dhcp_decode(RADIUS_PACKET *packet)
683 {
684         ssize_t i;
685         uint8_t *p;
686         uint32_t giaddr;
687         VALUE_PAIR *head, *vp, **tail;
688         VALUE_PAIR *maxms, *mtu;
689
690         head = NULL;
691         tail = &head;
692         p = packet->data;
693
694         if ((fr_debug_flag > 2) && fr_log_fp) {
695                 for (i = 0; i < packet->data_len; i++) {
696                         if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", (int) i);
697                         fprintf(fr_log_fp, "%02x ", packet->data[i]);
698                         if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
699                 }
700                 fprintf(fr_log_fp, "\n");
701         }
702
703         if (packet->data[1] != 1) {
704                 fr_strerror_printf("Packet is not Ethernet: %u",
705                       packet->data[1]);
706                 return -1;
707         }
708
709         /*
710          *      Decode the header.
711          */
712         for (i = 0; i < 14; i++) {
713                 vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
714                 if (!vp) {
715                         char buffer[256];
716                         strlcpy(buffer, fr_strerror(), sizeof(buffer));
717                         fr_strerror_printf("Cannot decode packet due to internal error: %s", buffer);
718                         pairfree(&head);
719                         return -1;
720                 }
721
722                 if ((i == 11) &&
723                     (packet->data[1] == 1) &&
724                     (packet->data[2] == 6)) {
725                         vp->type = PW_TYPE_ETHERNET;
726                 }
727
728                 switch (vp->type) {
729                 case PW_TYPE_BYTE:
730                         vp->vp_integer = p[0];
731                         vp->length = 1;
732                         break;
733
734                 case PW_TYPE_SHORT:
735                         vp->vp_integer = (p[0] << 8) | p[1];
736                         vp->length = 2;
737                         break;
738
739                 case PW_TYPE_INTEGER:
740                         memcpy(&vp->vp_integer, p, 4);
741                         vp->vp_integer = ntohl(vp->vp_integer);
742                         vp->length = 4;
743                         break;
744
745                 case PW_TYPE_IPADDR:
746                         memcpy(&vp->vp_ipaddr, p, 4);
747                         vp->length = 4;
748                         break;
749
750                 case PW_TYPE_STRING:
751                         memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
752                         vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
753                         vp->length = strlen(vp->vp_strvalue);
754                         if (vp->length == 0) {
755                                 pairfree(&vp);
756                         }
757                         break;
758
759                 case PW_TYPE_OCTETS:
760                         memcpy(vp->vp_octets, p, packet->data[2]);
761                         vp->length = packet->data[2];
762                         break;
763
764                 case PW_TYPE_ETHERNET:
765                         memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
766                         vp->length = sizeof(vp->vp_ether);
767                         break;
768
769                 default:
770                         fr_strerror_printf("BAD TYPE %d", vp->type);
771                         pairfree(&vp);
772                         break;
773                 }
774                 p += dhcp_header_sizes[i];
775
776                 if (!vp) continue;
777
778                 debug_pair(vp);
779                 *tail = vp;
780                 tail = &vp->next;
781         }
782
783         /*
784          *      Loop over the options.
785          */
786
787         /*
788          *      Nothing uses tail after this call, if it does in the future
789          *      it'll need to find the new tail...
790          *      FIXME: This should also check sname && file fields.
791          *      See the dhcp_get_option() function above.
792          */
793         if (fr_dhcp_decode_options(packet->data + 240, packet->data_len - 240,
794                                    tail) < 0) {
795                 return -1;
796         }
797
798         /*
799          *      If DHCP request, set ciaddr to zero.
800          */
801
802         /*
803          *      Set broadcast flag for broken vendors, but only if
804          *      giaddr isn't set.
805          */
806         memcpy(&giaddr, packet->data + 24, sizeof(giaddr));
807         if (giaddr == htonl(INADDR_ANY)) {
808                 /*
809                  *      DHCP Opcode is request
810                  */
811                 vp = pairfind(head, DHCP2ATTR(256));
812                 if (vp && vp->lvalue == 3) {
813                         /*
814                          *      Vendor is "MSFT 98"
815                          */
816                         vp = pairfind(head, DHCP2ATTR(63));
817                         if (vp && (strcmp(vp->vp_strvalue, "MSFT 98") == 0)) {
818                                 vp = pairfind(head, DHCP2ATTR(262));
819
820                                 /*
821                                  *      Reply should be broadcast.
822                                  */
823                                 if (vp) vp->lvalue |= 0x8000;
824                                 packet->data[10] |= 0x80;
825                         }
826                 }
827         }
828
829         /*
830          *      FIXME: Nuke attributes that aren't used in the normal
831          *      header for discover/requests.
832          */
833         packet->vps = head;
834
835         /*
836          *      Client can request a LARGER size, but not a smaller
837          *      one.  They also cannot request a size larger than MTU.
838          */
839         maxms = pairfind(packet->vps, DHCP2ATTR(57));
840         mtu = pairfind(packet->vps, DHCP2ATTR(26));
841
842         if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {
843                 fr_strerror_printf("DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification.");
844                 return -1;
845         }
846
847         if (maxms && (maxms->vp_integer < DEFAULT_PACKET_SIZE)) {
848                 fr_strerror_printf("DHCP WARNING: Client says maximum message size is smaller than minimum permitted by the specification: fixing it");
849                 maxms->vp_integer = DEFAULT_PACKET_SIZE;
850         }
851
852         if (maxms && mtu && (maxms->vp_integer > mtu->vp_integer)) {
853                 fr_strerror_printf("DHCP WARNING: Client says MTU is smaller than maximum message size: fixing it");
854                 maxms->vp_integer = mtu->vp_integer;
855         }
856
857         if (fr_debug_flag > 0) {
858                 for (vp = packet->vps; vp != NULL; vp = vp->next) {
859
860                 }
861         }
862
863         if (fr_debug_flag) fflush(stdout);
864
865         return 0;
866 }
867
868
869 static int attr_cmp(const void *one, const void *two)
870 {
871         const VALUE_PAIR * const *a = one;
872         const VALUE_PAIR * const *b = two;
873
874         /*
875          *      DHCP-Message-Type is first, for simplicity.
876          */
877         if (((*a)->attribute == DHCP2ATTR(53)) &&
878             (*b)->attribute != DHCP2ATTR(53)) return -1;
879
880         /*
881          *      Relay-Agent is last
882          */
883         if (((*a)->attribute == DHCP2ATTR(82)) &&
884             (*b)->attribute != DHCP2ATTR(82)) return +1;
885
886         return ((*a)->attribute - (*b)->attribute);
887 }
888
889
890 static size_t fr_dhcp_vp2attr(VALUE_PAIR *vp, uint8_t *p, size_t room)
891 {
892         size_t length;
893         uint32_t lvalue;
894
895         /*
896          *      FIXME: Check room!
897          */
898         room = room;            /* -Wunused */
899
900         /*
901          *      Search for all attributes of the same
902          *      type, and pack them into the same
903          *      attribute.
904          */
905         switch (vp->type) {
906         case PW_TYPE_BYTE:
907                 length = 1;
908                 *p = vp->vp_integer & 0xff;
909                 break;
910
911         case PW_TYPE_SHORT:
912                 length = 2;
913                 lvalue = htons(vp->vp_integer);
914                 memcpy(p, &lvalue, 2);
915                 break;
916
917         case PW_TYPE_INTEGER:
918                 length = 4;
919                 lvalue = htonl(vp->vp_integer);
920                 memcpy(p, &lvalue, 4);
921                 break;
922
923         case PW_TYPE_IPADDR:
924                 length = 4;
925                 memcpy(p, &vp->vp_ipaddr, 4);
926                 break;
927
928         case PW_TYPE_ETHERNET:
929                 length = 6;
930                 memcpy(p, &vp->vp_ether, 6);
931                 break;
932
933         case PW_TYPE_STRING:
934                 memcpy(p, vp->vp_strvalue, vp->length);
935                 length = vp->length;
936                 break;
937
938         case PW_TYPE_TLV:       /* FIXME: split it on 255? */
939                 memcpy(p, vp->vp_tlv, vp->length);
940                 length = vp->length;
941                 break;
942
943         case PW_TYPE_OCTETS:
944                 memcpy(p, vp->vp_octets, vp->length);
945                 length = vp->length;
946                 break;
947
948         default:
949                 fr_strerror_printf("BAD TYPE2 %d", vp->type);
950                 length = 0;
951                 break;
952         }
953
954         return length;
955 }
956
957 static VALUE_PAIR *fr_dhcp_vp2suboption(VALUE_PAIR *vps)
958 {
959         int length;
960         unsigned int attribute;
961         uint8_t *ptr;
962         VALUE_PAIR *vp, *tlv;
963
964         attribute = vps->attribute & 0xffff00ff;
965
966         tlv = paircreate(attribute, PW_TYPE_TLV);
967         if (!tlv) return NULL;
968
969         tlv->length = 0;
970         for (vp = vps; vp != NULL; vp = vp->next) {
971                 /*
972                  *      Group the attributes ONLY until we see a
973                  *      non-TLV attribute.
974                  */
975                 if (!vp->flags.is_tlv ||
976                     vp->flags.encoded ||
977                     ((vp->attribute & 0xffff00ff) != attribute)) {
978                         break;
979                 }
980
981                 tlv->length += vp->length + 2;
982         }
983
984         if (!tlv->length) {
985                 pairfree(&tlv);
986                 return NULL;
987         }
988
989         tlv->vp_tlv = malloc(tlv->length);
990         if (!tlv->vp_tlv) {
991                 pairfree(&tlv);
992                 return NULL;
993         }
994
995         ptr = tlv->vp_tlv;
996         for (vp = vps; vp != NULL; vp = vp->next) {
997                 if (!vp->flags.is_tlv ||
998                     vp->flags.encoded ||
999                     ((vp->attribute & 0xffff00ff) != attribute)) {
1000                         break;
1001                 }
1002
1003                 length = fr_dhcp_vp2attr(vp, ptr + 2,
1004                                          tlv->vp_tlv + tlv->length - ptr);
1005                 if (length > 255) {
1006                         pairfree(&tlv);
1007                         return NULL;
1008                 }
1009
1010                 /*
1011                  *      Pack the attribute.
1012                  */
1013                 ptr[0] = (vp->attribute & 0xff00) >> 8;
1014                 ptr[1] = length;
1015
1016                 ptr += length + 2;
1017                 vp->flags.encoded = 1;
1018         }
1019
1020         return tlv;
1021 }
1022
1023 int fr_dhcp_encode(RADIUS_PACKET *packet)
1024 {
1025         int i, num_vps;
1026         uint8_t *p;
1027         VALUE_PAIR *vp;
1028         uint32_t lvalue, mms;
1029         size_t dhcp_size, length;
1030 #ifndef NDEBUG
1031         const char *name;
1032 #ifdef WITH_UDPFROMTO
1033         char src_ip_buf[256];
1034 #endif
1035         char dst_ip_buf[256];
1036 #endif
1037
1038         if (packet->data) free(packet->data);
1039
1040         packet->data = malloc(MAX_PACKET_SIZE);
1041         packet->data_len = MAX_PACKET_SIZE;
1042         memset(packet->data, 0, packet->data_len);
1043
1044         /* XXX Ugly ... should be set by the caller */
1045         if (packet->code == 0) packet->code = PW_DHCP_NAK;
1046
1047 #ifndef NDEBUG
1048         if ((packet->code >= PW_DHCP_DISCOVER) &&
1049             (packet->code <= PW_DHCP_INFORM)) {
1050                 name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
1051         } else {
1052                 name = "?Unknown?";
1053         }
1054
1055         DEBUG(
1056 #ifdef WITH_UDPFROMTO
1057               "Encoding %s of id %08x from %s:%d to %s:%d\n",
1058 #else
1059               "Encoding %s of id %08x to %s:%d\n",
1060 #endif
1061               name, (unsigned int) packet->id,
1062 #ifdef WITH_UDPFROMTO
1063               inet_ntop(packet->src_ipaddr.af,
1064                         &packet->src_ipaddr.ipaddr,
1065                         src_ip_buf, sizeof(src_ip_buf)),
1066               packet->src_port,
1067 #endif
1068               inet_ntop(packet->dst_ipaddr.af,
1069                         &packet->dst_ipaddr.ipaddr,
1070                      dst_ip_buf, sizeof(dst_ip_buf)),
1071               packet->dst_port);
1072 #endif
1073
1074         p = packet->data;
1075
1076         mms = DEFAULT_PACKET_SIZE; /* maximum message size */
1077
1078         /*
1079          *      Clients can request a LARGER size, but not a
1080          *      smaller one.  They also cannot request a size
1081          *      larger than MTU.
1082          */
1083
1084         /* DHCP-DHCP-Maximum-Msg-Size */
1085         vp = pairfind(packet->vps, DHCP2ATTR(57));
1086         if (vp && (vp->vp_integer > mms)) {
1087                 mms = vp->vp_integer;
1088
1089                 if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;
1090         }
1091
1092         /*
1093          *      RFC 3118: Authentication option.
1094          */
1095         vp = pairfind(packet->vps, DHCP2ATTR(90));
1096         if (vp) {
1097                 if (vp->length < 2) {
1098                         memset(vp->vp_octets + vp->length, 0,
1099                                2 - vp->length);
1100                         vp->length = 2;
1101                 }
1102
1103                 if (vp->length < 3) {
1104                         struct timeval tv;
1105
1106                         gettimeofday(&tv, NULL);
1107                         vp->vp_octets[2] = 0;
1108                         timeval2ntp(&tv, vp->vp_octets + 3);
1109                         vp->length = 3 + 8;
1110                 }
1111
1112                 /*
1113                  *      Configuration token (clear-text token)
1114                  */
1115                 if (vp->vp_octets[0] == 0) {
1116                         VALUE_PAIR *pass;
1117                         vp->vp_octets[1] = 0;
1118
1119                         pass = pairfind(packet->vps, PW_CLEARTEXT_PASSWORD);
1120                         if (pass) {
1121                                 length = pass->length;
1122                                 if ((length + 11) > sizeof(vp->vp_octets)) {
1123                                         length -= ((length + 11) - sizeof(vp->vp_octets));
1124                                 }
1125                                 memcpy(vp->vp_octets + 11, pass->vp_strvalue,
1126                                        length);
1127                                 vp->length = length + 11;
1128                         } else {
1129                                 vp->length = 11 + 8;
1130                                 memset(vp->vp_octets + 11, 0, 8);
1131                                 vp->length = 11 + 8;
1132                         }
1133                 } else {        /* we don't support this type! */
1134                         fr_strerror_printf("DHCP-Authentication %d unsupported",
1135                                            vp->vp_octets[0]);
1136                 }
1137         }
1138
1139         /* DHCP-Opcode */
1140         if ((vp = pairfind(packet->vps, DHCP2ATTR(256)))) {
1141                 *p++ = vp->vp_integer & 0xff;
1142         } else {
1143                 *p++ = 1;       /* client message */
1144         }
1145
1146         /* DHCP-Hardware-Type */
1147         if ((vp = pairfind(packet->vps, DHCP2ATTR(257)))) {
1148                 *p++ = vp->vp_integer & 0xFF;
1149         } else {
1150                 *p++ = 1;               /* hardware type = ethernet */
1151         }
1152
1153         /* DHCP-Hardware-Address-Length */
1154         if ((vp = pairfind(packet->vps, DHCP2ATTR(258)))) {
1155                 *p++ = vp->vp_integer & 0xFF;
1156         } else {
1157                 *p++ = 6;               /* 6 bytes of ethernet */
1158         }
1159
1160         /* DHCP-Hop-Count */
1161         if ((vp = pairfind(packet->vps, DHCP2ATTR(259)))) {
1162                 *p = vp->vp_integer & 0xff;
1163         }
1164         p++;
1165
1166         /* DHCP-Transaction-Id */
1167         if ((vp = pairfind(packet->vps, DHCP2ATTR(260)))) {
1168                 lvalue = htonl(vp->vp_integer);
1169         } else {
1170                 lvalue = fr_rand();
1171         }
1172         memcpy(p, &lvalue, 4);
1173         p += 4;
1174
1175         /* DHCP-Number-of-Seconds */
1176         if ((vp = pairfind(packet->vps, DHCP2ATTR(261)))) {
1177                 lvalue = htonl(vp->vp_integer);
1178                 memcpy(p, &lvalue, 2);
1179         }
1180         p += 2;
1181
1182         /* DHCP-Flags */
1183         if ((vp = pairfind(packet->vps, DHCP2ATTR(262)))) {
1184                 lvalue = htons(vp->vp_integer);
1185                 memcpy(p, &lvalue, 2);
1186         }
1187         p += 2;
1188
1189         /* DHCP-Client-IP-Address */
1190         if ((vp = pairfind(packet->vps, DHCP2ATTR(263)))) {
1191                 memcpy(p, &vp->vp_ipaddr, 4);
1192         }
1193         p += 4;
1194
1195         /* DHCP-Your-IP-address */
1196         if ((vp = pairfind(packet->vps, DHCP2ATTR(264)))) {
1197                 lvalue = vp->vp_ipaddr;
1198         } else {
1199                 lvalue = htonl(INADDR_ANY);
1200         }
1201         memcpy(p, &lvalue, 4);
1202         p += 4;
1203
1204         /* DHCP-Server-IP-Address */
1205         vp = pairfind(packet->vps, DHCP2ATTR(265));
1206         if (vp) {
1207                 lvalue = vp->vp_ipaddr;
1208         } else {
1209                 lvalue = htonl(INADDR_ANY);
1210         }
1211         memcpy(p, &lvalue, 4);
1212         p += 4;
1213
1214         /*
1215          *      DHCP-Gateway-IP-Address
1216          */
1217         if (vp = pairfind(packet->vps, DHCP2ATTR(266))) {
1218                 lvalue = vp->vp_ipaddr;
1219         } else {
1220                 lvalue = htonl(INADDR_ANY);
1221         }
1222         memcpy(p, &lvalue, 4);
1223         p += 4;
1224
1225         /* DHCP-Client-Hardware-Address */
1226         if ((vp = pairfind(packet->vps, DHCP2ATTR(267)))) {
1227                 if (vp->length > DHCP_CHADDR_LEN) {
1228                         memcpy(p, vp->vp_octets, DHCP_CHADDR_LEN);
1229                 } else {
1230                         memcpy(p, vp->vp_octets, vp->length);
1231                 }
1232         }
1233         p += DHCP_CHADDR_LEN;
1234
1235         /* DHCP-Server-Host-Name */
1236         if ((vp = pairfind(packet->vps, DHCP2ATTR(268)))) {
1237                 if (vp->length > DHCP_SNAME_LEN) {
1238                         memcpy(p, vp->vp_strvalue, DHCP_SNAME_LEN);
1239                 } else {
1240                         memcpy(p, vp->vp_strvalue, vp->length);
1241                 }
1242         }
1243         p += DHCP_SNAME_LEN;
1244
1245         /*
1246          *      Copy over DHCP-Boot-Filename.
1247          *
1248          *      FIXME: This copy should be delayed until AFTER the options
1249          *      have been processed.  If there are too many options for
1250          *      the packet, then they go into the sname && filename fields.
1251          *      When that happens, the boot filename is passed as an option,
1252          *      instead of being placed verbatim in the filename field.
1253          */
1254
1255         /* DHCP-Boot-Filename */
1256         if ((vp = pairfind(packet->vps, DHCP2ATTR(269)))) {
1257                 if (vp->length > DHCP_FILE_LEN) {
1258                         memcpy(p, vp->vp_strvalue, DHCP_FILE_LEN);
1259                 } else {
1260                         memcpy(p, vp->vp_strvalue, vp->length);
1261                 }
1262         }
1263         p += DHCP_FILE_LEN;
1264
1265         /* DHCP magic number */
1266         lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER);
1267         memcpy(p, &lvalue, 4);
1268         p += 4;
1269
1270         /*
1271          *      Print the header.
1272          */
1273         if (fr_debug_flag > 1) {
1274                 uint8_t *pp = p;
1275
1276                 p = packet->data;
1277
1278                 for (i = 0; i < 14; i++) {
1279                         vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
1280                         if (!vp) {
1281                                 char buffer[256];
1282                                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1283                                 fr_strerror_printf("Cannot decode packet due to internal error: %s", buffer);
1284                                 return -1;
1285                         }
1286
1287                         switch (vp->type) {
1288                         case PW_TYPE_BYTE:
1289                                 vp->vp_integer = p[0];
1290                                 vp->length = 1;
1291                                 break;
1292
1293                         case PW_TYPE_SHORT:
1294                                 memcpy(&vp->vp_integer, p, 2);
1295                                 vp->vp_integer = ntohs(vp->vp_integer);
1296                                 vp->length = 2;
1297                                 break;
1298
1299                         case PW_TYPE_INTEGER:
1300                                 memcpy(&vp->vp_integer, p, 4);
1301                                 vp->vp_integer = ntohl(vp->vp_integer);
1302                                 vp->length = 4;
1303                                 break;
1304
1305                         case PW_TYPE_IPADDR:
1306                                 memcpy(&vp->vp_ipaddr, p, 4);
1307                                 vp->length = 4;
1308                                 break;
1309
1310                         case PW_TYPE_STRING:
1311                                 memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
1312                                 vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
1313                                 vp->length = strlen(vp->vp_strvalue);
1314                                 break;
1315
1316                         case PW_TYPE_OCTETS: /* only for Client HW Address */
1317                                 memcpy(vp->vp_octets, p, packet->data[2]);
1318                                 vp->length = packet->data[2];
1319                                 break;
1320
1321                         case PW_TYPE_ETHERNET: /* only for Client HW Address */
1322                                 memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
1323                                 vp->length = sizeof(vp->vp_ether);
1324                                 break;
1325
1326                         default:
1327                                 fr_strerror_printf("Internal sanity check failed %d %d", vp->type, __LINE__);
1328                                 pairfree(&vp);
1329                                 break;
1330                         }
1331
1332                         p += dhcp_header_sizes[i];
1333
1334                         debug_pair(vp);
1335                         pairfree(&vp);
1336                 }
1337
1338                 /*
1339                  *      Jump over DHCP magic number, response, etc.
1340                  */
1341                 p = pp;
1342         }
1343
1344         /*
1345          *      Before packing the attributes, re-order them so that
1346          *      the array ones are all contiguous.  This simplifies
1347          *      the later code.
1348          */
1349         num_vps = 0;
1350         for (vp = packet->vps; vp != NULL; vp = vp->next) {
1351                 num_vps++;
1352         }
1353         if (num_vps > 1) {
1354                 VALUE_PAIR **array, **last;
1355
1356                 array = malloc(num_vps * sizeof(VALUE_PAIR *));
1357
1358                 i = 0;
1359                 for (vp = packet->vps; vp != NULL; vp = vp->next) {
1360                         array[i++] = vp;
1361                 }
1362
1363                 /*
1364                  *      Sort the attributes.
1365                  */
1366                 qsort(array, (size_t) num_vps, sizeof(VALUE_PAIR *),
1367                       attr_cmp);
1368
1369                 last = &packet->vps;
1370                 for (i = 0; i < num_vps; i++) {
1371                         *last = array[i];
1372                         array[i]->next = NULL;
1373                         last = &(array[i]->next);
1374                 }
1375                 free(array);
1376         }
1377
1378         p[0] = 0x35;            /* DHCP-Message-Type */
1379         p[1] = 1;
1380         p[2] = packet->code - PW_DHCP_OFFSET;
1381         p += 3;
1382
1383         /*
1384          *      Pack in the attributes.
1385          */
1386         vp = packet->vps;
1387         while (vp) {
1388                 int num_entries = 1;
1389                 VALUE_PAIR *same;
1390                 uint8_t *plength, *pattr;
1391
1392                 if (!IS_DHCP_ATTR(vp)) goto next;
1393
1394                 /* DHCP-Message-Type (already done) */
1395                 if (vp->attribute == DHCP2ATTR(53)) goto next;
1396                 if (((vp->attribute & 0xffff) > 255) &&
1397                     (DHCP_BASE_ATTR(vp->attribute) != PW_DHCP_OPTION_82)) goto next;
1398
1399                 debug_pair(vp);
1400                 if (vp->flags.encoded) goto next;
1401
1402                 length = vp->length;
1403
1404                 for (same = vp->next; same != NULL; same = same->next) {
1405                         if (same->attribute != vp->attribute) break;
1406                         num_entries++;
1407                 }
1408
1409                 /*
1410                  *      For client-identifier
1411                  */
1412                 if ((vp->type == PW_TYPE_ETHERNET) &&
1413                     (vp->length == 6) &&
1414                     (num_entries == 1)) {
1415                         vp->type = PW_TYPE_OCTETS;
1416                         memmove(vp->vp_octets + 1, vp->vp_octets, 6);
1417                         vp->vp_octets[0] = 1;
1418                 }
1419
1420                 pattr = p;
1421                 *(p++) = vp->attribute & 0xff;
1422                 plength = p;
1423                 *(p++) = 0;     /* header isn't included in attr length */
1424
1425                 for (i = 0; i < num_entries; i++) {
1426                         if (i != 0) debug_pair(vp);
1427
1428                         if (vp->flags.is_tlv) {
1429                                 VALUE_PAIR *tlv;
1430
1431                                 /*
1432                                  *      Should NOT have been encoded yet!
1433                                  */
1434                                 tlv = fr_dhcp_vp2suboption(vp);
1435
1436                                 /*
1437                                  *      Ignore it if there's an issue
1438                                  *      encoding it.
1439                                  */
1440                                 if (!tlv) goto next;
1441
1442                                 tlv->next = vp->next;
1443                                 vp->next = tlv;
1444                                 vp = tlv;
1445                         }
1446
1447                         length = fr_dhcp_vp2attr(vp, p, 0);
1448
1449                         /*
1450                          *      This will never happen due to FreeRADIUS
1451                          *      limitations: sizeof(vp->vp_octets) < 255
1452                          */
1453                         if (length > 255) {
1454                                 fr_strerror_printf("WARNING Ignoring too long attribute %s!", vp->name);
1455                                 break;
1456                         }
1457
1458                         /*
1459                          *      More than one attribute of the same type
1460                          *      in a row: they are packed together
1461                          *      into the same TLV.  If we overflow,
1462                          *      go bananas!
1463                          */
1464                         if ((*plength + length) > 255) {
1465                                 fr_strerror_printf("WARNING Ignoring too long attribute %s!", vp->name);
1466                                 break;
1467                         }
1468
1469                         *plength += length;
1470                         p += length;
1471
1472                         if (vp->next &&
1473                             (vp->next->attribute == vp->attribute))
1474                                 vp = vp->next;
1475                 } /* loop over num_entries */
1476
1477         next:
1478                 vp = vp->next;
1479         }
1480
1481         p[0] = 0xff;            /* end of option option */
1482         p[1] = 0x00;
1483         p += 2;
1484         dhcp_size = p - packet->data;
1485
1486         /*
1487          *      FIXME: if (dhcp_size > mms),
1488          *        then we put the extra options into the "sname" and "file"
1489          *        fields, AND set the "end option option" in the "options"
1490          *        field.  We also set the "overload option",
1491          *        and put options into the "file" field, followed by
1492          *        the "sname" field.  Where each option is completely
1493          *        enclosed in the "file" and/or "sname" field, AND
1494          *        followed by the "end of option", and MUST be followed
1495          *        by padding option.
1496          *
1497          *      Yuck.  That sucks...
1498          */
1499         packet->data_len = dhcp_size;
1500
1501         if (packet->data_len < DEFAULT_PACKET_SIZE) {
1502                 memset(packet->data + packet->data_len, 0,
1503                        DEFAULT_PACKET_SIZE - packet->data_len);
1504                 packet->data_len = DEFAULT_PACKET_SIZE;
1505         }
1506
1507         if ((fr_debug_flag > 2) && fr_log_fp) {
1508                 for (i = 0; i < packet->data_len; i++) {
1509                         if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", i);
1510                         fprintf(fr_log_fp, "%02x ", packet->data[i]);
1511                         if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
1512                 }
1513                 fprintf(fr_log_fp, "\n");
1514         }
1515
1516         return 0;
1517 }
1518
1519 int fr_dhcp_add_arp_entry(int fd, const char *interface,
1520                           VALUE_PAIR *macaddr, VALUE_PAIR *ip)
1521 {
1522 #ifdef SIOCSARP
1523         struct sockaddr_in *sin;
1524         struct arpreq req;
1525
1526         if (!interface) {
1527                 fr_strerror_printf("No interface specified.  Cannot update ARP table");
1528                 return -1;
1529         }
1530
1531         if (macaddr->length > sizeof (req.arp_ha.sa_data)) {
1532                 fr_strerror_printf("ERROR: DHCP only supports up to %zu octets for "
1533                                    "Client Hardware Address (got %zu octets)\n",
1534                                    sizeof(req.arp_ha.sa_data),
1535                                    macaddr->length);
1536                 return -1;
1537         }
1538
1539         memset(&req, 0, sizeof(req));
1540         sin = (struct sockaddr_in *) &req.arp_pa;
1541         sin->sin_family = AF_INET;
1542         sin->sin_addr.s_addr = ip->vp_ipaddr;
1543         strlcpy(req.arp_dev, interface, sizeof(req.arp_dev));
1544         memcpy(&req.arp_ha.sa_data, macaddr->vp_octets, macaddr->length);
1545
1546         req.arp_flags = ATF_COM;
1547         if (ioctl(fd, SIOCSARP, &req) < 0) {
1548                 fr_strerror_printf("DHCP: Failed to add entry in ARP cache: %s (%d)",
1549                                    strerror(errno), errno);
1550                 return -1;
1551         }
1552
1553         return 0;
1554 #else
1555         fd = fd;
1556         interface = interface;
1557         macaddr = macaddr;
1558         ip = ip;
1559
1560         fr_strerror_printf("Adding ARP entry is unsupported on this system");
1561         return -1;
1562 #endif
1563 }
1564
1565 #endif /* WITH_DHCP */