if pidfile turned out to be !regular file, do not unlink it.
[oweals/busybox.git] / networking / udhcp / options.c
index d75bc5aff60a0fc369385ea38aaab8b54bfb1da9..3168fc69aa68d9e6d60c306b0831c7190934fc4f 100644 (file)
@@ -1,60 +1,70 @@
+/* vi: set sw=4 ts=4: */
 /*
  * options.c -- DHCP server option packet tools
  * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
  */
 
-#include <stdlib.h>
-#include <string.h>
-
+#include "common.h"
 #include "dhcpd.h"
-#include "files.h"
 #include "options.h"
-#include "common.h"
 
 
 /* supported options are easily added here */
-struct dhcp_option dhcp_options[] = {
-       /* name[10]     flags                                   code */
-       {"subnet",      OPTION_IP | OPTION_REQ,                 0x01},
-       {"timezone",    OPTION_S32,                             0x02},
-       {"router",      OPTION_IP | OPTION_LIST | OPTION_REQ,   0x03},
-       {"timesvr",     OPTION_IP | OPTION_LIST,                0x04},
-       {"namesvr",     OPTION_IP | OPTION_LIST,                0x05},
-       {"dns",         OPTION_IP | OPTION_LIST | OPTION_REQ,   0x06},
-       {"logsvr",      OPTION_IP | OPTION_LIST,                0x07},
-       {"cookiesvr",   OPTION_IP | OPTION_LIST,                0x08},
-       {"lprsvr",      OPTION_IP | OPTION_LIST,                0x09},
-       {"hostname",    OPTION_STRING | OPTION_REQ,             0x0c},
-       {"bootsize",    OPTION_U16,                             0x0d},
-       {"domain",      OPTION_STRING | OPTION_REQ,             0x0f},
-       {"swapsvr",     OPTION_IP,                              0x10},
-       {"rootpath",    OPTION_STRING,                          0x11},
-       {"ipttl",       OPTION_U8,                              0x17},
-       {"mtu",         OPTION_U16,                             0x1a},
-       {"broadcast",   OPTION_IP | OPTION_REQ,                 0x1c},
-       {"ntpsrv",      OPTION_IP | OPTION_LIST,                0x2a},
-       {"wins",        OPTION_IP | OPTION_LIST,                0x2c},
-       {"requestip",   OPTION_IP,                              0x32},
-       {"lease",       OPTION_U32,                             0x33},
-       {"dhcptype",    OPTION_U8,                              0x35},
-       {"serverid",    OPTION_IP,                              0x36},
-       {"message",     OPTION_STRING,                          0x38},
-       {"tftp",        OPTION_STRING,                          0x42},
-       {"bootfile",    OPTION_STRING,                          0x43},
-       {"",            0x00,                           0x00}
+const struct dhcp_option dhcp_options[] = {
+       /* name[12]     flags                                   code */
+       {"subnet",      OPTION_IP | OPTION_REQ,                 0x01},
+       {"timezone",    OPTION_S32,                             0x02},
+       {"router",      OPTION_IP | OPTION_LIST | OPTION_REQ,   0x03},
+       {"timesvr",     OPTION_IP | OPTION_LIST,                0x04},
+       {"namesvr",     OPTION_IP | OPTION_LIST,                0x05},
+       {"dns",         OPTION_IP | OPTION_LIST | OPTION_REQ,   0x06},
+       {"logsvr",      OPTION_IP | OPTION_LIST,                0x07},
+       {"cookiesvr",   OPTION_IP | OPTION_LIST,                0x08},
+       {"lprsvr",      OPTION_IP | OPTION_LIST,                0x09},
+       {"hostname",    OPTION_STRING | OPTION_REQ,             0x0c},
+       {"bootsize",    OPTION_U16,                             0x0d},
+       {"domain",      OPTION_STRING | OPTION_LIST | OPTION_REQ, 0x0f},
+       {"swapsvr",     OPTION_IP,                              0x10},
+       {"rootpath",    OPTION_STRING,                          0x11},
+       {"ipttl",       OPTION_U8,                              0x17},
+       {"mtu",         OPTION_U16,                             0x1a},
+       {"broadcast",   OPTION_IP | OPTION_REQ,                 0x1c},
+       {"nisdomain",   OPTION_STRING | OPTION_REQ,             0x28},
+       {"nissrv",      OPTION_IP | OPTION_LIST | OPTION_REQ,   0x29},
+       {"ntpsrv",      OPTION_IP | OPTION_LIST | OPTION_REQ,   0x2a},
+       {"wins",        OPTION_IP | OPTION_LIST,                0x2c},
+       {"requestip",   OPTION_IP,                              0x32},
+       {"lease",       OPTION_U32,                             0x33},
+       {"dhcptype",    OPTION_U8,                              0x35},
+       {"serverid",    OPTION_IP,                              0x36},
+       {"message",     OPTION_STRING,                          0x38},
+       {"vendorclass", OPTION_STRING,                          0x3C},
+       {"clientid",    OPTION_STRING,                          0x3D},
+       {"tftp",        OPTION_STRING,                          0x42},
+       {"bootfile",    OPTION_STRING,                          0x43},
+       {"userclass",   OPTION_STRING,                          0x4D},
+#if ENABLE_FEATURE_RFC3397
+       {"search",      OPTION_STR1035 | OPTION_LIST | OPTION_REQ, 0x77},
+#endif
+       /* MSIE's "Web Proxy Autodiscovery Protocol" support */
+       {"wpad",        OPTION_STRING,                          0xfc},
+       {"",            0x00,                                   0x00}
 };
 
 /* Lengths of the different option types */
-int option_lengths[] = {
-       [OPTION_IP] =           4,
-       [OPTION_IP_PAIR] =      8,
-       [OPTION_BOOLEAN] =      1,
-       [OPTION_STRING] =       1,
-       [OPTION_U8] =           1,
-       [OPTION_U16] =          2,
-       [OPTION_S16] =          2,
-       [OPTION_U32] =          4,
-       [OPTION_S32] =          4
+const unsigned char option_lengths[] ALIGN1 = {
+       [OPTION_IP] =      4,
+       [OPTION_IP_PAIR] = 8,
+       [OPTION_BOOLEAN] = 1,
+       [OPTION_STRING] =  1,
+#if ENABLE_FEATURE_RFC3397
+       [OPTION_STR1035] = 1,
+#endif
+       [OPTION_U8] =      1,
+       [OPTION_U16] =     2,
+       [OPTION_S16] =     2,
+       [OPTION_U32] =     4,
+       [OPTION_S32] =     4
 };
 
 
@@ -70,12 +80,12 @@ uint8_t *get_option(struct dhcpMessage *packet, int code)
        length = 308;
        while (!done) {
                if (i >= length) {
-                       LOG(LOG_WARNING, "bogus packet, option fields too long.");
+                       bb_error_msg("bogus packet, option fields too long");
                        return NULL;
                }
                if (optionptr[i + OPT_CODE] == code) {
                        if (i + 1 + optionptr[i + OPT_LEN] >= length) {
-                               LOG(LOG_WARNING, "bogus packet, option fields too long.");
+                               bb_error_msg("bogus packet, option fields too long");
                                return NULL;
                        }
                        return optionptr + i + 2;
@@ -86,7 +96,7 @@ uint8_t *get_option(struct dhcpMessage *packet, int code)
                        break;
                case DHCP_OPTION_OVER:
                        if (i + 1 + optionptr[i + OPT_LEN] >= length) {
-                               LOG(LOG_WARNING, "bogus packet, option fields too long.");
+                               bb_error_msg("bogus packet, option fields too long");
                                return NULL;
                        }
                        over = optionptr[i + 3];
@@ -134,10 +144,11 @@ int add_option_string(uint8_t *optionptr, uint8_t *string)
 
        /* end position + string length + option code/length + end option */
        if (end + string[OPT_LEN] + 2 + 1 >= 308) {
-               LOG(LOG_ERR, "Option 0x%02x did not fit into the packet!", string[OPT_CODE]);
+               bb_error_msg("option 0x%02x did not fit into the packet",
+                               string[OPT_CODE]);
                return 0;
        }
-       DEBUG(LOG_INFO, "adding option 0x%02x", string[OPT_CODE]);
+       DEBUG("adding option 0x%02x", string[OPT_CODE]);
        memcpy(optionptr + end, string, string[OPT_LEN] + 2);
        optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
        return string[OPT_LEN] + 2;
@@ -147,82 +158,23 @@ int add_option_string(uint8_t *optionptr, uint8_t *string)
 /* add a one to four byte option to a packet */
 int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data)
 {
-       char length = 0;
-       int i;
-       uint8_t option[2 + 4];
-       uint8_t *u8;
-       uint16_t *u16;
-       uint32_t *u32;
-       uint32_t aligned;
-       u8 = (uint8_t *) &aligned;
-       u16 = (uint16_t *) &aligned;
-       u32 = &aligned;
-
-       for (i = 0; dhcp_options[i].code; i++)
-               if (dhcp_options[i].code == code) {
-                       length = option_lengths[dhcp_options[i].flags & TYPE_MASK];
+       const struct dhcp_option *dh;
+
+       for (dh = dhcp_options; dh->code; dh++) {
+               if (dh->code == code) {
+                       uint8_t option[6], len;
+
+                       option[OPT_CODE] = code;
+                       len = option_lengths[dh->flags & TYPE_MASK];
+                       option[OPT_LEN] = len;
+                       if (BB_BIG_ENDIAN) data <<= 8 * (4 - len);
+                       /* This memcpy is for broken processors which can't
+                        * handle a simple unaligned 32-bit assignment */
+                       memcpy(&option[OPT_DATA], &data, 4);
+                       return add_option_string(optionptr, option);
                }
-
-       if (!length) {
-               DEBUG(LOG_ERR, "Could not add option 0x%02x", code);
-               return 0;
        }
 
-       option[OPT_CODE] = code;
-       option[OPT_LEN] = length;
-
-       switch (length) {
-               case 1: *u8 =  data; break;
-               case 2: *u16 = data; break;
-               case 4: *u32 = data; break;
-       }
-       memcpy(option + 2, &aligned, length);
-       return add_option_string(optionptr, option);
-}
-
-
-/* find option 'code' in opt_list */
-struct option_set *find_option(struct option_set *opt_list, char code)
-{
-       while (opt_list && opt_list->data[OPT_CODE] < code)
-               opt_list = opt_list->next;
-
-       if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list;
-       else return NULL;
-}
-
-
-/* add an option to the opt_list */
-void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length)
-{
-       struct option_set *existing, *new, **curr;
-
-       /* add it to an existing option */
-       if ((existing = find_option(*opt_list, option->code))) {
-               DEBUG(LOG_INFO, "Attaching option %s to existing member of list", option->name);
-               if (option->flags & OPTION_LIST) {
-                       if (existing->data[OPT_LEN] + length <= 255) {
-                               existing->data = realloc(existing->data,
-                                               existing->data[OPT_LEN] + length + 2);
-                               memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
-                               existing->data[OPT_LEN] += length;
-                       } /* else, ignore the data, we could put this in a second option in the future */
-               } /* else, ignore the new data */
-       } else {
-               DEBUG(LOG_INFO, "Attaching option %s to list", option->name);
-
-               /* make a new option */
-               new = xmalloc(sizeof(struct option_set));
-               new->data = xmalloc(length + 2);
-               new->data[OPT_CODE] = option->code;
-               new->data[OPT_LEN] = length;
-               memcpy(new->data + 2, buffer, length);
-
-               curr = opt_list;
-               while (*curr && (*curr)->data[OPT_CODE] < option->code)
-                       curr = &(*curr)->next;
-
-               new->next = *curr;
-               *curr = new;
-       }
+       bb_error_msg("cannot add option 0x%02x", code);
+       return 0;
 }