[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 4/7] slirp: Add translator of DHCP vendor option str
From: |
Fedor Lyakhov |
Subject: |
[Qemu-devel] [PATCH 4/7] slirp: Add translator of DHCP vendor option string to DHCP TLV representation |
Date: |
Sat, 26 Apr 2014 02:11:00 +0400 |
New module dhcp_vendopt.c provides translate_dhcp_vendopt() function to convert
command-line DHCP vendor option string into internal DHCP TLV (tag-length-
value) uint8_t buffer. The buffer is stored in global Slirp instance.
Signed-off-by: Fedor Lyakhov <address@hidden>
---
slirp/Makefile.objs | 1 +
slirp/dhcp_vendopt.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++
slirp/slirp.c | 5 ++
slirp/slirp.h | 5 ++
4 files changed, 174 insertions(+)
create mode 100644 slirp/dhcp_vendopt.c
diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
index 2daa9dc..b8c60c7 100644
--- a/slirp/Makefile.objs
+++ b/slirp/Makefile.objs
@@ -1,3 +1,4 @@
common-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o dnssearch.o
common-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
+common-obj-y += dhcp_vendopt.o
diff --git a/slirp/dhcp_vendopt.c b/slirp/dhcp_vendopt.c
new file mode 100644
index 0000000..274a35f
--- /dev/null
+++ b/slirp/dhcp_vendopt.c
@@ -0,0 +1,163 @@
+/*
+ * dhcp_vendoropt.c: adds vendor-specific options (option 43) to DHCP Offer/Ack
+ *
+ * Copyright (c) 2014 Fedor Lyakhov <address@hidden>
+ *
+ * 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 3 of the License, or (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "bootp_defines.h"
+#include "slirp.h"
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <glib.h>
+
+/* Delimiters for vendor-specific options specified from the command-line */
+#define VENDOR_OPTION_DELIMITER ";"
+#define VENDOR_TAG_DELIMITER ":"
+/* Maximum number of tag digits in null-terminated string form */
+#define TAG_MAX_DIGITS 3
+
+/**
+ * parse_option:
+ * @option: Single DHCP vendor option null-terminated string (MUST NOT be NULL)
+ * @ptag: [out] Tag of the option
+ * @plen: [out] Length of the option value
+ * @pvalue: [out] Value of the option
+ *
+ * Parses DHCP vendor option string in TLV format.
+ *
+ * Zero tag is returned in case of non-TLV format, value will be pointing
+ * to the original option string.
+ *
+ * If option string starts with zero tag "0:", it is treated like non-TLV,
+ * but the tag will be stripped from the value.
+ */
+static void parse_option(char *option, uint8_t *ptag, size_t *plen,
+ char **pvalue);
+
+/**
+ * translate_dhcp_vendopt:
+ * @slirp: Pointer to Slirp struct to store the translated DHCP vendor option
+ * in a binary TLV form. MUST NOT be NULL.
+ * @dhcp_vendopt_string: Null-terminated string of DHCP vendor options.
+ *
+ * Translates DHCP vendor option string to binary representation to be written
+ * to DHCP packet. This binary representation is uint8_t buffer in TLV format.
+ * The buffer and its length are stored in the @slirp struct.
+ *
+ * Returns: zero if translation succeeded, non-zero otherwise.
+ */
+int translate_dhcp_vendopt(Slirp *slirp, const char *dhpc_vendopt_string)
+{
+ uint8_t options_buf[OPT_HEADER_LEN + MAX_OPT_LEN];
+ uint8_t *buf = options_buf + OPT_HEADER_LEN;
+ /* Total length of vendor option field, excluding top TL header */
+ size_t total_length = 0;
+ char *options;
+ char *current_option;
+ char *option_value;
+ size_t option_length;
+ uint8_t option_tag;
+
+ /* Copying string because strtok will modify it */
+ options = g_strdup(dhpc_vendopt_string);
+ if (!options) {
+ return 1;
+ }
+
+ current_option = strtok(options, VENDOR_OPTION_DELIMITER);
+ if (!current_option) { /* Strtok returns only non-empty strings or NULL */
+ goto cleanup;
+ }
+
+ parse_option(current_option, &option_tag, &option_length, &option_value);
+
+ if (!option_tag) { /* Zero tag - single vendor option case */
+ total_length = option_length;
+ if (total_length > MAX_OPT_LEN) {
+ DEBUG_MISC((dfd, "Too long DHCP vendor option is specified, "
+ "skipping it"));
+ goto cleanup;
+ }
+ memcpy(buf, option_value, total_length);
+ } else {
+ /* Multiple vendor options are specified, writing them in TLV format */
+ do {
+ size_t new_total_length = total_length + option_length
+ + OPT_HEADER_LEN;
+ if (new_total_length > MAX_OPT_LEN) {
+ DEBUG_MISC((dfd, "Maximum DHCP options size is reached at "
+ "option: %s, skipping it and the rest\n",
+ current_option));
+ break;
+ }
+ total_length = (uint8_t) new_total_length;
+
+ *buf++ = option_tag;
+ *buf++ = (uint8_t) option_length;
+ memcpy(buf, option_value, option_length);
+ buf += option_length;
+
+ current_option = strtok(NULL, VENDOR_OPTION_DELIMITER);
+ if (current_option) {
+ parse_option(current_option, &option_tag, &option_length,
+ &option_value);
+ }
+ } while (current_option && option_tag);
+ }
+
+ if (total_length > 0) {
+ /* Writing top TLV header */
+ options_buf[0] = RFC1533_VENDOR;
+ options_buf[1] = (uint8_t) total_length;
+ slirp->dhcp_vendopt_len = total_length + OPT_HEADER_LEN;
+ slirp->dhcp_vendopt = g_memdup(options_buf, slirp->dhcp_vendopt_len);
+ }
+
+cleanup:
+ g_free(options);
+ return 0;
+}
+
+static void parse_option(char *option, uint8_t *ptag, size_t *plen,
+ char **pvalue)
+{
+ char tag_digits[TAG_MAX_DIGITS + 1] = {0, 0, 0, 0};
+ int i;
+
+ *pvalue = option;
+ *ptag = 0;
+
+ for (i = 0; (i < TAG_MAX_DIGITS) && (*option)
+ && (*option != VENDOR_TAG_DELIMITER[0]) && (isdigit(*option)); i++) {
+ tag_digits[i] = *option++; /* Collecting tag digits, if any */
+ }
+
+ if ((i > 0) && (i <= TAG_MAX_DIGITS)
+ && (*option == VENDOR_TAG_DELIMITER[0])) {
+ int res = atoi(tag_digits);
+ /* Only 1-254 tags are allowed by RFC2132, but we accept 0 tag below
+ as an indicator for tag-less value, i.e. we strip initial 0: */
+ if ((res >= 0) && (res < UINT8_MAX)) {
+ *ptag = (uint8_t) res;
+ ++option; /* removing delimiter from the value */
+ *pvalue = option;
+ }
+ }
+ *plen = strlen(*pvalue);
+}
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 3dfce46..c0435d3 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -234,6 +234,10 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
translate_dnssearch(slirp, vdnssearch);
}
+ if (dhpc_vendopt_string) {
+ translate_dhcp_vendopt(slirp, dhpc_vendopt_string);
+ }
+
slirp->opaque = opaque;
register_savevm(NULL, "slirp", 0, 3,
@@ -254,6 +258,7 @@ void slirp_cleanup(Slirp *slirp)
m_cleanup(slirp);
g_free(slirp->vdnssearch);
+ g_free(slirp->dhcp_vendopt);
g_free(slirp->tftp_prefix);
g_free(slirp->bootp_filename);
g_free(slirp);
diff --git a/slirp/slirp.h b/slirp/slirp.h
index e4a1bd4..f5882bc 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -239,6 +239,8 @@ struct Slirp {
char *bootp_filename;
size_t vdnssearch_len;
uint8_t *vdnssearch;
+ size_t dhcp_vendopt_len;
+ uint8_t *dhcp_vendopt;
/* tcp states */
struct socket tcb;
@@ -301,6 +303,9 @@ void lprint(const char *, ...) GCC_FMT_ATTR(1, 2);
/* dnssearch.c */
int translate_dnssearch(Slirp *s, const char ** names);
+/* dhcp_vendopt.c */
+int translate_dhcp_vendopt(Slirp *s, const char *dhpc_vendopt_string);
+
/* cksum.c */
int cksum(struct mbuf *m, int len);
--
1.8.4.5
- [Qemu-devel] [PATCH 0/7] slirp: Add support of vendor-specific info option to built-in DHCP server, Fedor Lyakhov, 2014/04/25
- [Qemu-devel] [PATCH 4/7] slirp: Add translator of DHCP vendor option string to DHCP TLV representation,
Fedor Lyakhov <=
- [Qemu-devel] [PATCH 7/7] slirp: Add unit test for slirp/dhcp_vendopt.c module, Fedor Lyakhov, 2014/04/25
- [Qemu-devel] [PATCH 1/7] slirp: Move BOOTP/DHCP protocol defines to a separate header, Fedor Lyakhov, 2014/04/25
- [Qemu-devel] [PATCH 2/7] slirp: Add header inclusion guard to slirp/debug.h, Fedor Lyakhov, 2014/04/25
- [Qemu-devel] [PATCH 3/7] slirp: Add new command-line suboption "[, dhcpvendopt=optstring]" to "-net user", Fedor Lyakhov, 2014/04/25
- [Qemu-devel] [PATCH 5/7] slirp: Add DHCP vendor option to DHCP Offer/Ack packet, Fedor Lyakhov, 2014/04/25
- [Qemu-devel] [PATCH 6/7] slirp: Add description of new "dhcpvendopt" suboption to the help and man page, Fedor Lyakhov, 2014/04/25