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