Fix compile warnings
[freeradius.git] / src / lib / dhcp.c
index 5ac7676..98b8aac 100644 (file)
@@ -3,18 +3,18 @@
  *
  * Version:    $Id$
  *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
+ *   This library is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU Lesser General Public
+ *   License as published by the Free Software Foundation; either
+ *   version 2.1 of the License, or (at your option) any later version.
  *
- *   This program is distributed in the hope that it will be useful,
+ *   This library is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *   Lesser General Public License for more details.
  *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
  * Copyright 2008 The FreeRADIUS server project
@@ -28,6 +28,11 @@ RCSID("$Id$")
 #include <freeradius-devel/udpfromto.h>
 #include <freeradius-devel/dhcp.h>
 
+/*
+ *     This doesn't appear to work right now.
+ */
+#undef WITH_UDPFROMTO
+
 #ifdef WITH_DHCP
 #define DHCP_CHADDR_LEN        (16)
 #define DHCP_SNAME_LEN (64)
@@ -239,7 +244,7 @@ RADIUS_PACKET *fr_dhcp_recv(int sockfd)
 
        if (packet->data_len < MIN_PACKET_SIZE) {
                fr_strerror_printf("DHCP packet is too small (%d < %d)",
-                     packet->data_len, MIN_PACKET_SIZE);
+                                  (int) packet->data_len, MIN_PACKET_SIZE);
                rad_free(&packet);
                return NULL;
        }
@@ -429,7 +434,7 @@ static int decode_tlv(VALUE_PAIR *tlv, const uint8_t *data, size_t data_len)
 
        p = data;
        while (p < (data + data_len)) {
-               vp = paircreate(tlv->attribute | (p[0] << 8), PW_TYPE_OCTETS);
+               vp = paircreate(tlv->attribute | (p[0] << 8), DHCP_MAGIC_VENDOR, PW_TYPE_OCTETS);
                if (!vp) {
                        pairfree(&head);
                        goto make_tlv;
@@ -650,7 +655,7 @@ int fr_dhcp_decode(RADIUS_PACKET *packet)
                        continue;
                }
                                
-               da = dict_attrbyvalue(DHCP2ATTR(p[0]));
+               da = dict_attrbyvalue(p[0], DHCP_MAGIC_VENDOR);
                if (!da) {
                        fr_strerror_printf("Attribute not in our dictionary: %u",
                              p[0]);
@@ -705,7 +710,7 @@ int fr_dhcp_decode(RADIUS_PACKET *packet)
                        /*
                         *      Hack for ease of use.
                         */
-                       if ((da->attr == DHCP2ATTR(0x3d)) &&
+                       if ((da->attr == 0x3d) &&
                            !da->flags.array &&
                            (alen == 7) && (*p == 1) && (num_entries == 1)) {
                                vp->type = PW_TYPE_ETHERNET;
@@ -740,19 +745,19 @@ int fr_dhcp_decode(RADIUS_PACKET *packet)
                /*
                 *      DHCP Opcode is request
                 */
-               vp = pairfind(head, DHCP2ATTR(256));
-               if (vp && vp->lvalue == 3) {
+               vp = pairfind(head, 256, DHCP_MAGIC_VENDOR);
+               if (vp && vp->vp_integer == 3) {
                        /*
                         *      Vendor is "MSFT 98"
                         */
-                       vp = pairfind(head, DHCP2ATTR(63));
+                       vp = pairfind(head, 63, DHCP_MAGIC_VENDOR);
                        if (vp && (strcmp(vp->vp_strvalue, "MSFT 98") == 0)) {
-                               vp = pairfind(head, DHCP2ATTR(262));
+                               vp = pairfind(head, 262, DHCP_MAGIC_VENDOR);
 
                                /*
                                 *      Reply should be broadcast.
                                 */
-                               if (vp) vp->lvalue |= 0x8000;
+                               if (vp) vp->vp_integer |= 0x8000;
                                packet->data[10] |= 0x80;                       
                        }
                }
@@ -768,8 +773,8 @@ int fr_dhcp_decode(RADIUS_PACKET *packet)
         *      Client can request a LARGER size, but not a smaller
         *      one.  They also cannot request a size larger than MTU.
         */
-       maxms = pairfind(packet->vps, DHCP2ATTR(57));
-       mtu = pairfind(packet->vps, DHCP2ATTR(26));
+       maxms = pairfind(packet->vps, 57, DHCP_MAGIC_VENDOR);
+       mtu = pairfind(packet->vps, 26, DHCP_MAGIC_VENDOR);
 
        if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {
                fr_strerror_printf("DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification.");
@@ -806,14 +811,14 @@ static int attr_cmp(const void *one, const void *two)
        /*
         *      DHCP-Message-Type is first, for simplicity.
         */
-       if (((*a)->attribute == DHCP2ATTR(53)) &&
-           (*b)->attribute != DHCP2ATTR(53)) return -1;
+       if (((*a)->attribute == 53) &&
+           (*b)->attribute != 53) return -1;
 
        /*
         *      Relay-Agent is last
         */
-       if (((*a)->attribute == DHCP2ATTR(82)) &&
-           (*b)->attribute != DHCP2ATTR(82)) return +1;
+       if (((*a)->attribute == 82) &&
+           (*b)->attribute != 82) return +1;
 
        return ((*a)->attribute - (*b)->attribute);
 }
@@ -895,7 +900,7 @@ static VALUE_PAIR *fr_dhcp_vp2suboption(VALUE_PAIR *vps)
 
        attribute = vps->attribute & 0xffff00ff;
 
-       tlv = paircreate(attribute, PW_TYPE_TLV);
+       tlv = paircreate(attribute, DHCP_MAGIC_VENDOR, PW_TYPE_TLV);
        if (!tlv) return NULL;
 
        tlv->length = 0;
@@ -905,7 +910,7 @@ static VALUE_PAIR *fr_dhcp_vp2suboption(VALUE_PAIR *vps)
                 *      non-TLV attribute.
                 */
                if (!vp->flags.is_tlv ||
-                   vp->flags.encoded ||
+                   vp->flags.extended ||
                    ((vp->attribute & 0xffff00ff) != attribute)) {
                        break;
                }
@@ -927,7 +932,7 @@ static VALUE_PAIR *fr_dhcp_vp2suboption(VALUE_PAIR *vps)
        ptr = tlv->vp_tlv;
        for (vp = vps; vp != NULL; vp = vp->next) {
                if (!vp->flags.is_tlv ||
-                   vp->flags.encoded ||
+                   vp->flags.extended ||
                    ((vp->attribute & 0xffff00ff) != attribute)) {
                        break;
                }
@@ -943,7 +948,7 @@ static VALUE_PAIR *fr_dhcp_vp2suboption(VALUE_PAIR *vps)
                ptr[1] = length;
 
                ptr += length + 2;
-               vp->flags.encoded = 1;
+               vp->flags.extended = 1;
        }
 
        return tlv;
@@ -1069,6 +1074,16 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
                                 &packet->dst_ipaddr.ipaddr,
                                 dst_ip_buf, sizeof(dst_ip_buf)),
                       packet->dst_port);
+
+               if (fr_debug_flag) {
+                       for (i = 256; i < 269; i++) {
+                               vp = pairfind(packet->vps, i,
+                                             DHCP_MAGIC_VENDOR);
+                               if (!vp) continue;
+
+                               debug_pair(vp);
+                       }
+               }
        }
 
        p = packet->data;
@@ -1081,7 +1096,7 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
                 *      smaller one.  They also cannot request a size
                 *      larger than MTU.
                 */
-               vp = pairfind(original->vps, DHCP2ATTR(57));
+               vp = pairfind(original->vps, 57, DHCP_MAGIC_VENDOR);
                if (vp && (vp->vp_integer > mms)) {
                        mms = vp->vp_integer;
                        
@@ -1092,7 +1107,7 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
        /*
         *      RFC 3118: Authentication option.
         */
-       vp = pairfind(packet->vps, DHCP2ATTR(90));
+       vp = pairfind(packet->vps, 90, DHCP_MAGIC_VENDOR);
        if (vp) {
                if (vp->length < 2) {
                        memset(vp->vp_octets + vp->length, 0,
@@ -1116,7 +1131,7 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
                        VALUE_PAIR *pass;
                        vp->vp_octets[1] = 0;
 
-                       pass = pairfind(packet->vps, PW_CLEARTEXT_PASSWORD);
+                       pass = pairfind(packet->vps, PW_CLEARTEXT_PASSWORD, DHCP_MAGIC_VENDOR);
                        if (pass) {
                                length = pass->length;
                                if ((length + 11) > sizeof(vp->vp_octets)) {
@@ -1136,14 +1151,25 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
                }
        }
 
-       if (!original) {
-               *p++ = 1;       /* client message */
+       vp = pairfind(packet->vps, 256, DHCP_MAGIC_VENDOR);
+       if (vp) {
+               *p++ = vp->vp_integer & 0xff;
        } else {
-               *p++ = 2;       /* server message */
+               if (!original) {
+                       *p++ = 1;       /* client message */
+               } else {
+                       *p++ = 2;       /* server message */
+               }
        }
        *p++ = 1;               /* hardware type = ethernet */
        *p++ = 6;               /* 6 bytes of ethernet */
-       *p++ = 0;               /* hops */
+
+       vp = pairfind(packet->vps, 259, DHCP_MAGIC_VENDOR);
+       if (vp) {
+               *p++ = vp->vp_integer & 0xff;
+       } else {
+               *p++ = 0;               /* hops */
+       }
 
        if (original) { /* Xid */
                memcpy(p, original->data + 4, 4);
@@ -1163,7 +1189,7 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
        /*
         *      Allow the admin to set the broadcast flag.
         */
-       vp = pairfind(packet->vps, DHCP2ATTR(262));
+       vp = pairfind(packet->vps, 262, DHCP_MAGIC_VENDOR);
        if (vp) {
                p[0] |= (vp->vp_integer & 0xff00) >> 8;
                p[1] |= (vp->vp_integer & 0xff);
@@ -1174,7 +1200,7 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
        /*
         *      Set client IP address.
         */
-       vp = pairfind(packet->vps, DHCP2ATTR(264)); /* Your IP address */
+       vp = pairfind(packet->vps, 264, DHCP_MAGIC_VENDOR); /* Your IP address */
        if (vp) {
                lvalue = vp->vp_ipaddr;
        } else {
@@ -1183,8 +1209,8 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
        memcpy(p, &lvalue, 4);  /* your IP address */
        p += 4;
 
-       vp = pairfind(packet->vps, DHCP2ATTR(265)); /* server IP address */
-       if (!vp) vp = pairfind(packet->vps, DHCP2ATTR(54)); /* identifier */
+       vp = pairfind(packet->vps, 265, DHCP_MAGIC_VENDOR); /* server IP address */
+       if (!vp) vp = pairfind(packet->vps, 54, DHCP_MAGIC_VENDOR); /* identifier */
        if (vp) {
                lvalue = vp->vp_ipaddr;
        } else {
@@ -1196,7 +1222,7 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
        if (original) {
                memcpy(p, original->data + 24, 4); /* copy gateway IP address */
        } else {
-               vp = pairfind(packet->vps, DHCP2ATTR(266));
+               vp = pairfind(packet->vps, 266, DHCP_MAGIC_VENDOR);
                if (vp) {
                        lvalue = vp->vp_ipaddr;
                } else {
@@ -1209,7 +1235,7 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
        if (original) {
                memcpy(p, original->data + 28, DHCP_CHADDR_LEN);
        } else {
-               vp = pairfind(packet->vps, DHCP2ATTR(267));
+               vp = pairfind(packet->vps, 267, DHCP_MAGIC_VENDOR);
                if (vp) {
                        if (vp->length > DHCP_CHADDR_LEN) {
                                memcpy(p, vp->vp_octets, DHCP_CHADDR_LEN);
@@ -1235,7 +1261,7 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
         *      When that happens, the boot filename is passed as an option,
         *      instead of being placed verbatim in the filename field.
         */
-       vp = pairfind(packet->vps, DHCP2ATTR(269));
+       vp = pairfind(packet->vps, 269, DHCP_MAGIC_VENDOR);
        if (vp) {
                if (vp->length > DHCP_FILE_LEN) {
                        memcpy(p, vp->vp_strvalue, DHCP_FILE_LEN);
@@ -1369,13 +1395,13 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
                VALUE_PAIR *same;
                uint8_t *plength, *pattr;
 
-               if (!IS_DHCP_ATTR(vp)) goto next;
-               if (vp->attribute == DHCP2ATTR(53)) goto next; /* already done */
+               if (vp->vendor != DHCP_MAGIC_VENDOR) goto next;
+               if (vp->attribute == 53) goto next; /* already done */
                if ((vp->attribute > 255) &&
                    (DHCP_BASE_ATTR(vp->attribute) != PW_DHCP_OPTION_82)) goto next;
 
                debug_pair(vp);
-               if (vp->flags.encoded) goto next;
+               if (vp->flags.extended) goto next;
 
                length = vp->length;
 
@@ -1507,4 +1533,46 @@ int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
 
        return 0;
 }
+
+int fr_dhcp_add_arp_entry(int fd, const char *interface,
+                         VALUE_PAIR *macaddr, VALUE_PAIR *ip)
+{
+#ifdef SIOCSARP
+       struct sockaddr_in *sin
+       struct arpreq req;
+
+       if (macaddr->length > sizeof (req.arp_ha.sa_data)) {
+               fr_strerror_printf("ERROR: DHCP only supports up to %d octets for "
+                                  "Client Hardware Address (got %d octets)\n",
+                                  sizeof(req.arp_ha.sa_data),
+                                  macaddr->length);
+               return -1;
+       }
+
+       memset(&req, 0, sizeof(req));
+       sin = (struct sockaddr_in *) &req.arp_pa;
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = ip->vp_ipaddr;
+       strlcpy(req.arp_dev, interface, sizeof(req.arp_dev));
+       memcpy(&req.arp_ha.sa_data, macaddr->vp_octets, macaddr->length);
+
+       req.arp_flags = ATF_COM;
+       if (ioctl(fd, SIOCSARP, &req) < 0) {
+               fr_strerror_printf("DHCP: Failed to add entry in ARP cache: %s (%d)",
+                                  strerror(errno), errno);
+               return -1;
+       }
+
+       return 0;
+#else
+       fd = fd;                /* -Wunused */
+       interface = interface;  /* -Wunused */
+       macaddr = macaddr;      /* -Wunused */
+       ip = ip;                /* -Wunused */
+
+       fr_strerror_printf("Adding ARP entry is unsupported on this system");
+       return -1;
+#endif
+}
+
 #endif /* WITH_DHCP */