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