Added an option scanner to udhcp to enable iteration over packet options.

Signed-off-by: Martin Lewis <[email protected]>
---
 networking/udhcp/common.c | 96 ++++++++++++++++++++++++++---------------------
 networking/udhcp/common.h |  8 ++++
 2 files changed, 62 insertions(+), 42 deletions(-)

diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 16bf69707..20d843bab 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -15,7 +15,7 @@ const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
 };
 
 #if ENABLE_UDHCPC || ENABLE_UDHCPD
-/* Supported options are easily added here.
+/* Supported options are easily added here, they need to be sorted.
  * See RFC2132 for more options.
  * OPTION_REQ: these options are requested by udhcpc (unless -o).
  */
@@ -222,79 +222,91 @@ unsigned FAST_FUNC udhcp_option_idx(const char *name, 
const char *option_strings
        }
 }
 
-/* Get an option with bounds checking (warning, result is not aligned) */
-uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
+/* Initialize state to be used between subsequent udhcp_scan_options calls */
+void FAST_FUNC init_scan_state(struct dhcp_packet *packet, struct 
dhcp_scan_state *scan_state)
+{
+       scan_state->overload = 0;
+       scan_state->rem = sizeof(packet->options);
+       scan_state->optionptr = packet->options;
+}
+
+/* Iterate over packet's options, each call returning the next option.
+ * scan_state needs to be initialized with init_scan_state beforehand.
+ * Warning, result is not aligned. */
+uint8_t* FAST_FUNC udhcp_scan_options(struct dhcp_packet *packet, struct 
dhcp_scan_state *scan_state)
 {
-       uint8_t *optionptr;
        int len;
-       int rem;
-       int overload = 0;
        enum {
                FILE_FIELD101  = FILE_FIELD  * 0x101,
                SNAME_FIELD101 = SNAME_FIELD * 0x101,
        };
 
        /* option bytes: [code][len][data1][data2]..[dataLEN] */
-       optionptr = packet->options;
-       rem = sizeof(packet->options);
        while (1) {
-               if (rem <= 0) {
+               if (scan_state->rem <= 0) {
  complain:
                        bb_simple_error_msg("bad packet, malformed option 
field");
                        return NULL;
                }
 
                /* DHCP_PADDING and DHCP_END have no [len] byte */
-               if (optionptr[OPT_CODE] == DHCP_PADDING) {
-                       rem--;
-                       optionptr++;
+               if (scan_state->optionptr[OPT_CODE] == DHCP_PADDING) {
+                       scan_state->rem--;
+                       scan_state->optionptr++;
                        continue;
                }
-               if (optionptr[OPT_CODE] == DHCP_END) {
-                       if ((overload & FILE_FIELD101) == FILE_FIELD) {
+               if (scan_state->optionptr[OPT_CODE] == DHCP_END) {
+                       if ((scan_state->overload & FILE_FIELD101) == 
FILE_FIELD) {
                                /* can use packet->file, and didn't look at it 
yet */
-                               overload |= FILE_FIELD101; /* "we looked at it" 
*/
-                               optionptr = packet->file;
-                               rem = sizeof(packet->file);
+                               scan_state->overload |= FILE_FIELD101; /* "we 
looked at it" */
+                               scan_state->optionptr = packet->file;
+                               scan_state->rem = sizeof(packet->file);
                                continue;
                        }
-                       if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
+                       if ((scan_state->overload & SNAME_FIELD101) == 
SNAME_FIELD) {
                                /* can use packet->sname, and didn't look at it 
yet */
-                               overload |= SNAME_FIELD101; /* "we looked at 
it" */
-                               optionptr = packet->sname;
-                               rem = sizeof(packet->sname);
+                               scan_state->overload |= SNAME_FIELD101; /* "we 
looked at it" */
+                               scan_state->optionptr = packet->sname;
+                               scan_state->rem = sizeof(packet->sname);
                                continue;
                        }
                        break;
                }
 
-               if (rem <= OPT_LEN)
+               if (scan_state->rem <= OPT_LEN)
                        goto complain; /* complain and return NULL */
-               len = 2 + optionptr[OPT_LEN];
-               rem -= len;
-               if (rem < 0)
+               len = 2 + scan_state->optionptr[OPT_LEN];
+               scan_state->rem -= len;
+               /* So far no valid option with length 0 known. */
+               if (scan_state->rem < 0 || scan_state->optionptr[OPT_LEN] == 0)
                        goto complain; /* complain and return NULL */
 
-               if (optionptr[OPT_CODE] == code) {
-                       if (optionptr[OPT_LEN] == 0) {
-                               /* So far no valid option with length 0 known.
-                                * Having this check means that searching
-                                * for DHCP_MESSAGE_TYPE need not worry
-                                * that returned pointer might be unsafe
-                                * to dereference.
-                                */
-                               goto complain; /* complain and return NULL */
-                       }
-                       log_option("option found", optionptr);
-                       return optionptr + OPT_DATA;
+               if (scan_state->optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
+                       if (len >= 3)
+                               scan_state->overload |= 
scan_state->optionptr[OPT_DATA];
+               } else {
+                       uint8_t *return_ptr = scan_state->optionptr;
+                       scan_state->optionptr += len;
+                       return return_ptr;
                }
+               scan_state->optionptr += len;
+       }
 
-               if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
-                       if (len >= 3)
-                               overload |= optionptr[OPT_DATA];
-                       /* fall through */
+       return NULL;
+}
+
+/* Get an option with bounds checking (warning, result is not aligned) */
+uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
+{
+       uint8_t *optptr;
+       struct dhcp_scan_state scan_state;
+
+       init_scan_state(packet, &scan_state);
+       while ((optptr = udhcp_scan_options(packet, &scan_state)) != NULL) {
+               if (optptr[OPT_CODE] == code) {
+                       log_option("option found", optptr);
+                       return optptr + OPT_DATA;
                }
-               optionptr += len;
        }
 
        /* log3 because udhcpc uses it a lot - very noisy */
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 6214db06a..81c1dcbdc 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -107,6 +107,12 @@ enum {
        OPTION_LIST = 0x20,
 };
 
+struct dhcp_scan_state {
+       int overload;
+       int rem;
+       uint8_t *optionptr;
+};
+
 /* DHCP option codes (partial list). See RFC 2132 and
  * http://www.iana.org/assignments/bootp-dhcp-parameters/
  * Commented out options are handled by common option machinery,
@@ -206,6 +212,8 @@ extern const uint8_t dhcp_option_lengths[] ALIGN1;
 
 unsigned FAST_FUNC udhcp_option_idx(const char *name, const char 
*option_strings);
 
+void init_scan_state(struct dhcp_packet *packet, struct dhcp_scan_state 
*scan_state) FAST_FUNC;
+uint8_t *udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_scan_state 
*scan_state) FAST_FUNC;
 uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC;
 /* Same as above + ensures that option length is 4 bytes
  * (returns NULL if size is different)
-- 
2.11.0

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to