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