]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/dhcp_options.c
xnu-4570.51.1.tar.gz
[apple/xnu.git] / bsd / netinet / dhcp_options.c
index f6114a058c1237a09c10da6bd148bc6a8784e198..db54e59d55c069eb2746e76ae8b31588cff1c814 100644 (file)
@@ -1,3 +1,30 @@
+/*
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
 /*
  * dhcp_options.c
  * - routines to parse and access dhcp options
  * - imported from bootp project
  */
 
+#include <string.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <netinet/in.h>
 #include <sys/malloc.h>
-
 #include <netinet/dhcp.h>
 #include <netinet/dhcp_options.h>
 
+#ifndef TEST_DHCP_OPTIONS
+#include <libkern/libkern.h>
+
+#ifdef DHCP_DEBUG
+#define        dprintf(x) printf x;
+#else  /* !DHCP_DEBUG */
+#define        dprintf(x)
+#endif /* DHCP_DEBUG */
+
 static __inline__ void
 my_free(void * ptr)
 {
@@ -45,6 +81,19 @@ my_realloc(void * oldptr, int oldsize, int newsize)
     my_free(oldptr);
     return (data);
 }
+#else
+/*
+ * To build:
+ * xcrun -sdk macosx.internal cc -DTEST_DHCP_OPTIONS -o /tmp/dhcp_options dhcp_options.c -I .. 
+ */
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#define my_free        free
+#define my_malloc malloc
+#define my_realloc(ptr, old_size, new_size) realloc(ptr, new_size)
+#define        dprintf(x) printf x;
+#endif
 
 /*
  * Functions: ptrlist_*
@@ -79,7 +128,7 @@ ptrlist_count(ptrlist_t * list)
     return (list->count);
 }
 
-static void *
+static const void *
 ptrlist_element(ptrlist_t * list, int i)
 {
     if (list->array == NULL)
@@ -100,9 +149,7 @@ ptrlist_grow(ptrlist_t * list)
        list->array = my_malloc(sizeof(*list->array) * list->size);
     }
     else if (list->size == list->count) {
-#ifdef DEBUG
-       printf("doubling %d to %d\n", list->size, list->size * 2);
-#endif DEBUG
+       dprintf(("doubling %d to %d\n", list->size, list->size * 2));
        list->array = my_realloc(list->array, 
                                 sizeof(*list->array) * list->size,
                                 sizeof(*list->array) * list->size * 2);
@@ -114,7 +161,7 @@ ptrlist_grow(ptrlist_t * list)
 }
 
 static boolean_t
-ptrlist_add(ptrlist_t * list, void * element)
+ptrlist_add(ptrlist_t * list, const void * element)
 {
     if (ptrlist_grow(list) == FALSE)
        return (FALSE);
@@ -156,7 +203,7 @@ ptrlist_concat(ptrlist_t * list, ptrlist_t * extra)
  *   Routines to parse/access existing options buffers.
  */
 boolean_t
-dhcpol_add(dhcpol_t * list, void * element)
+dhcpol_add(dhcpol_t * list, const void * element)
 {
     return (ptrlist_add((ptrlist_t *)list, element));
 }
@@ -167,7 +214,7 @@ dhcpol_count(dhcpol_t * list)
     return (ptrlist_count((ptrlist_t *)list));
 }
 
-void *
+const void *
 dhcpol_element(dhcpol_t * list, int i)
 {
     return (ptrlist_element((ptrlist_t *)list, i));
@@ -201,27 +248,25 @@ dhcpol_concat(dhcpol_t * list, dhcpol_t * extra)
  *   the end tag.
  */
 boolean_t
-dhcpol_parse_buffer(dhcpol_t * list, void * buffer, int length,
-                   unsigned char * err)
+dhcpol_parse_buffer(dhcpol_t * list, const void * buffer, int length)
 {
     int                        len;
-    unsigned char *    scan;
-    unsigned char      tag;
-
-    if (err)
-       err[0] = '\0';
+    const uint8_t *    scan;
+    uint8_t            tag;
 
     dhcpol_init(list);
 
     len = length;
     tag = dhcptag_pad_e;
-    for (scan = (unsigned char *)buffer; tag != dhcptag_end_e && len > 0; ) {
+    for (scan = (const uint8_t *)buffer;
+        tag != dhcptag_end_e && len > DHCP_TAG_OFFSET; ) {
 
        tag = scan[DHCP_TAG_OFFSET];
 
        switch (tag) {
          case dhcptag_end_e:
-             dhcpol_add(list, scan); /* remember that it was terminated */
+             /* remember that it was terminated */
+             dhcpol_add(list, scan);
              scan++;
              len--;
              break;
@@ -229,20 +274,24 @@ dhcpol_parse_buffer(dhcpol_t * list, void * buffer, int length,
              scan++;
              len--;
              break;
-         default: {
-             unsigned char     option_len = scan[DHCP_LEN_OFFSET];
-           
-             dhcpol_add(list, scan);
-             len -= (option_len + 2);
-             scan += (option_len + 2);
+         default:
+             if (len > DHCP_LEN_OFFSET) {
+                 uint8_t       option_len;
+
+                 option_len = scan[DHCP_LEN_OFFSET];
+                 dhcpol_add(list, scan);
+                 len -= (option_len + DHCP_OPTION_OFFSET);
+                 scan += (option_len + DHCP_OPTION_OFFSET);
+             }
+             else {
+                 len = -1;
+             }
              break;
-         }
        }
     }
     if (len < 0) {
        /* ran off the end */
-       if (err)
-           sprintf(err, "parse failed near tag %d", tag);
+       dprintf(("dhcp_options: parse failed near tag %d\n", tag));
        dhcpol_free(list);
        return (FALSE);
     }
@@ -261,7 +310,7 @@ dhcpol_parse_buffer(dhcpol_t * list, void * buffer, int length,
  *   calls will retrieve the next occurence of the option.
  *   Before the first call, *start should be set to 0.
  */
-void *
+const void *
 dhcpol_find(dhcpol_t * list, int tag, int * len_p, int * start)
 {
     int        i = 0;
@@ -273,7 +322,7 @@ dhcpol_find(dhcpol_t * list, int tag, int * len_p, int * start)
        i = *start;
 
     for (; i < dhcpol_count(list); i++) {
-       unsigned char * option = dhcpol_element(list, i);
+       const uint8_t *         option = dhcpol_element(list, i);
        
        if (option[DHCP_TAG_OFFSET] == tag) {
            if (len_p)
@@ -286,47 +335,6 @@ dhcpol_find(dhcpol_t * list, int tag, int * len_p, int * start)
     return (NULL);
 }
 
-/*
- * Function: dhcpol_get
- * 
- * Purpose:
- *   Accumulate all occurences of the given option into a
- *   malloc'd buffer, and return its length.  Used to get
- *   all occurrences of a particular option in a single
- *   data area.
- * Note:
- *   Use _FREE(val, M_TEMP) to free the returned data area.
- */
-void *
-dhcpol_get(dhcpol_t * list, int tag, int * len_p)
-{
-    int        i;
-    char *     data = NULL;
-    int                data_len = 0;
-
-    if (tag == dhcptag_end_e || tag == dhcptag_pad_e)
-       return (NULL);
-
-    for (i = 0; i < dhcpol_count(list); i++) {
-       unsigned char * option = dhcpol_element(list, i);
-       
-       if (option[DHCP_TAG_OFFSET] == tag) {
-           int len = option[DHCP_LEN_OFFSET];
-
-           if (data_len == 0) {
-               data = my_malloc(len);
-           }
-           else {
-               data = my_realloc(data, data_len, data_len + len);
-           }
-           bcopy(option + DHCP_OPTION_OFFSET, data + data_len, len);
-           data_len += len;
-       }
-    }
-    *len_p = data_len;
-    return (data);
-}
-
 /*
  * Function: dhcpol_parse_packet
  *
@@ -339,46 +347,38 @@ dhcpol_get(dhcpol_t * list, int tag, int * len_p)
  *    then parses pkt->dp_sname if specified.
  */
 boolean_t
-dhcpol_parse_packet(dhcpol_t * options, struct dhcp * pkt, int len,
-                   unsigned char * err)
+dhcpol_parse_packet(dhcpol_t * options, const struct dhcp * pkt, int len)
 {
     char               rfc_magic[4] = RFC_OPTIONS_MAGIC;
 
     dhcpol_init(options);      /* make sure it's empty */
 
-    if (err)
-       err[0] = '\0';
-
     if (len < (sizeof(*pkt) + RFC_MAGIC_SIZE)) {
-       if (err) {
-           sprintf(err, "packet is too short: %d < %d",
-                   len, (int)sizeof(*pkt) + RFC_MAGIC_SIZE);
-       }
+       dprintf(("dhcp_options: packet is too short: %d < %d\n",
+                len, (int)sizeof(*pkt) + RFC_MAGIC_SIZE));
        return (FALSE);
     }
     if (bcmp(pkt->dp_options, rfc_magic, RFC_MAGIC_SIZE)) {
-       if (err)
-           sprintf(err, "missing magic number");
+       dprintf(("dhcp_options: missing magic number\n"));
        return (FALSE);
     }
     if (dhcpol_parse_buffer(options, pkt->dp_options + RFC_MAGIC_SIZE,
-                           len - sizeof(*pkt) - RFC_MAGIC_SIZE, err) == FALSE)
+                           len - sizeof(*pkt) - RFC_MAGIC_SIZE) == FALSE)
        return (FALSE);
     { /* get overloaded options */
-       unsigned char * overload;
+       const uint8_t * overload;
        int             overload_len;
 
-       overload = (unsigned char *)
-           dhcpol_find(options, dhcptag_option_overload_e, 
-                               &overload_len, NULL);
+       overload = dhcpol_find(options, dhcptag_option_overload_e, 
+                              &overload_len, NULL);
        if (overload && overload_len == 1) { /* has overloaded options */
            dhcpol_t    extra;
-
+           
            dhcpol_init(&extra);
            if (*overload == DHCP_OVERLOAD_FILE
                || *overload == DHCP_OVERLOAD_BOTH) {
                if (dhcpol_parse_buffer(&extra, pkt->dp_file, 
-                                        sizeof(pkt->dp_file), NULL)) {
+                                       sizeof(pkt->dp_file))) {
                    dhcpol_concat(options, &extra);
                    dhcpol_free(&extra);
                }
@@ -386,7 +386,7 @@ dhcpol_parse_packet(dhcpol_t * options, struct dhcp * pkt, int len,
            if (*overload == DHCP_OVERLOAD_SNAME
                || *overload == DHCP_OVERLOAD_BOTH) {
                if (dhcpol_parse_buffer(&extra, pkt->dp_sname, 
-                                        sizeof(pkt->dp_sname), NULL)) {
+                                       sizeof(pkt->dp_sname))) {
                    dhcpol_concat(options, &extra);
                    dhcpol_free(&extra);
                }
@@ -396,70 +396,17 @@ dhcpol_parse_packet(dhcpol_t * options, struct dhcp * pkt, int len,
     return (TRUE);
 }
 
-/*
- * Function: dhcpol_parse_vendor
- *
- * Purpose:
- *   Given a set of options, find the vendor specific option(s)
- *   and parse all of them into a single option list.
- *  
- * Return value:
- *   TRUE if vendor specific options existed and were parsed succesfully,
- *   FALSE otherwise.
- */
-boolean_t
-dhcpol_parse_vendor(dhcpol_t * vendor, dhcpol_t * options,
-                   unsigned char * err)
-{
-    dhcpol_t           extra;
-    boolean_t          ret = FALSE;
-    int                start = 0;
-
-    if (err)
-       err[0] = '\0';
-
-    dhcpol_init(vendor);
-    dhcpol_init(&extra);
-
-    for (;;) {
-       void *          data;
-       int             len;
-
-       data = dhcpol_find(options, dhcptag_vendor_specific_e, &len, &start);
-       if (data == NULL) {
-           break; /* out of for */
-       }
-
-       if (dhcpol_parse_buffer(&extra, data, len, err) == FALSE) {
-           goto failed;
-       }
-
-       if (dhcpol_concat(vendor, &extra) == FALSE) {
-           if (err)
-               sprintf(err, "dhcpol_concat() failed at %d\n", start);
-           goto failed;
-       }
-       dhcpol_free(&extra);
-       ret = TRUE;
-    }
-    if (ret == FALSE) {
-       if (err)
-           strcpy(err, "missing vendor specific options");
-    }
-    return (ret);
-
- failed:
-    dhcpol_free(vendor);
-    dhcpol_free(&extra);
-    return (FALSE);
-}
-
 #ifdef TEST_DHCP_OPTIONS
 char test_empty[] = {
     99, 130, 83, 99,
     255,
 };
 
+char test_short[] = {
+    99, 130, 83, 99,
+    1,
+};
+
 char test_simple[] = {
     99, 130, 83, 99,
     1, 4, 255, 255, 252, 0,
@@ -487,7 +434,7 @@ char test_no_end[] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-char test_too_short[] = {
+char test_no_magic[] = {
     0x1 
 };
 struct test {
@@ -502,7 +449,8 @@ struct test tests[] = {
     { "simple", test_simple, sizeof(test_simple), TRUE },
     { "vendor", test_vendor, sizeof(test_vendor), TRUE },
     { "no_end", test_no_end, sizeof(test_no_end), TRUE },
-    { "too_short", test_too_short, sizeof(test_too_short), FALSE },
+    { "no magic", test_no_magic, sizeof(test_no_magic), FALSE },
+    { "short", test_short, sizeof(test_short), FALSE },
     { NULL, NULL, 0, FALSE },
 };
 
@@ -514,7 +462,6 @@ main()
 {
     int        i;
     dhcpol_t   options;
-    char       error[256];
     struct dhcp * pkt = (struct dhcp *)buf;
 
     dhcpol_init(&options);
@@ -523,21 +470,15 @@ main()
        printf("\nTest %d: ", i);
        bcopy(tests[i].data, pkt->dp_options, tests[i].len);
        if (dhcpol_parse_packet(&options, pkt, 
-                               sizeof(*pkt) + tests[i].len,
-                               error) != tests[i].result) {
+                               sizeof(*pkt) + tests[i].len)
+           != tests[i].result) {
            printf("test '%s' FAILED\n", tests[i].name);
-           if (tests[i].result == TRUE) {
-               printf("error message returned was %s\n", error);
-           }
        }
        else {
            printf("test '%s' PASSED\n", tests[i].name);
-           if (tests[i].result == FALSE) {
-               printf("error message returned was %s\n", error);
-           }
        }
        dhcpol_free(&options);
     }
     exit(0);
 }
-#endif TEST_DHCP_OPTIONS
+#endif /* TEST_DHCP_OPTIONS */