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