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