[systemd-devel] [PATCH v2 05/26] dhcp: Add option appending and parsing
Patrik Flykt
patrik.flykt at linux.intel.com
Sun Nov 24 23:13:21 PST 2013
Add functions to append and parse DHCP options. Not all options
are passed to the callback function, the ones not exposed are
pad, end, message type and overload. If indicated by the overload
option, file and sname fields will be examined for more options.
The option functions are internal to DHCP, add a new header files
for interal function prototypes.
---
v2: fix __ prefix
src/dhcp/internal.h | 34 ++++++++++
src/dhcp/option.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 215 insertions(+)
create mode 100644 src/dhcp/internal.h
create mode 100644 src/dhcp/option.c
diff --git a/src/dhcp/internal.h b/src/dhcp/internal.h
new file mode 100644
index 0000000..328ef1c
--- /dev/null
+++ b/src/dhcp/internal.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Intel Corporation. All rights reserved.
+
+ systemd 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.
+
+ systemd 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdint.h>
+
+#include "protocol.h"
+
+int dhcp_option_append(uint8_t **buf, int *buflen, uint8_t code,
+ uint8_t optlen, const void *optval);
+
+typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len, uint8_t *option,
+ void *user_data);
+int dhcp_option_parse(DHCPMessage *message, int32_t len,
+ dhcp_option_cb_t cb, void *user_data);
diff --git a/src/dhcp/option.c b/src/dhcp/option.c
new file mode 100644
index 0000000..34aa98a
--- /dev/null
+++ b/src/dhcp/option.c
@@ -0,0 +1,181 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Intel Corporation. All rights reserved.
+
+ systemd 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.
+
+ systemd 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "internal.h"
+
+int dhcp_option_append(uint8_t **buf, int *buflen, uint8_t code,
+ uint8_t optlen, const void *optval)
+{
+ if (!buf || !buflen)
+ return -EINVAL;
+
+ switch (code) {
+
+ case DHCP_OPTION_PAD:
+ case DHCP_OPTION_END:
+ if (*buflen < 1)
+ return -ENOBUFS;
+
+ (*buf)[0] = code;
+ *buf += 1;
+ *buflen -= 1;
+ break;
+
+ default:
+ if (*buflen < optlen + 2)
+ return -ENOBUFS;
+
+ if (!optval)
+ return -EINVAL;
+
+ (*buf)[0] = code;
+ (*buf)[1] = optlen;
+ memcpy(&(*buf)[2], optval, optlen);
+
+ *buf += optlen + 2;
+ *buflen -= (optlen + 2);
+
+ break;
+ }
+
+ return 0;
+}
+
+static int parse_options(uint8_t *buf, int32_t buflen, int *overload,
+ int *message_type, dhcp_option_cb_t cb,
+ void *user_data)
+{
+ uint8_t *code = buf;
+ uint8_t *len;
+
+ while (buflen > 0) {
+ switch (*code) {
+ case DHCP_OPTION_PAD:
+ buflen -= 1;
+ code++;
+ break;
+
+ case DHCP_OPTION_END:
+ return 0;
+
+ case DHCP_OPTION_MESSAGE_TYPE:
+ buflen -= 3;
+ if (buflen < 0)
+ return -ENOBUFS;
+
+ len = code + 1;
+ if (*len != 1)
+ return -EINVAL;
+
+ if (message_type)
+ *message_type = *(len + 1);
+
+ code += 3;
+
+ break;
+
+ case DHCP_OPTION_OVERLOAD:
+ buflen -= 3;
+ if (buflen < 0)
+ return -ENOBUFS;
+
+ len = code + 1;
+ if (*len != 1)
+ return -EINVAL;
+
+ if (overload)
+ *overload = *(len + 1);
+
+ code += 3;
+
+ break;
+
+ default:
+ if (buflen < 3)
+ return -ENOBUFS;
+
+ len = code + 1;
+ buflen -= *len + 2;
+
+ if (buflen < 0)
+ return -EINVAL;
+
+ if (cb)
+ cb(*code, *len, len + 1, user_data);
+
+ code += *len + 2;
+
+ break;
+ }
+ }
+
+ if (buflen)
+ return -EINVAL;
+
+ return 0;
+}
+
+int dhcp_option_parse(DHCPMessage *message, int32_t len,
+ dhcp_option_cb_t cb, void *user_data)
+{
+ int overload = 0;
+ int message_type = -ENOMSG;
+ uint8_t *opt = (uint8_t *)(message + 1);
+ int res;
+
+ if (message == NULL || len < 0)
+ return -EINVAL;
+
+ len -= sizeof(DHCPMessage);
+ len -= 4;
+ if (len < 0)
+ return -EINVAL;
+
+ if (opt[0] != 0x63 && opt[1] != 0x82 && opt[2] != 0x53 &&
+ opt[3] != 0x63)
+ return -EINVAL;
+
+ res = parse_options(&opt[4], len, &overload, &message_type,
+ cb, user_data);
+ if (res < 0)
+ return res;
+
+ if (overload & DHCP_OVERLOAD_FILE) {
+ res = parse_options(message->file, sizeof(message->file),
+ NULL, &message_type, cb, user_data);
+ if (res < 0)
+ return res;
+ }
+
+ if (overload & DHCP_OVERLOAD_SNAME) {
+ res = parse_options(message->sname, sizeof(message->sname),
+ NULL, &message_type, cb, user_data);
+ if (res < 0)
+ return res;
+ }
+
+ return message_type;
+}
--
1.7.10.4
More information about the systemd-devel
mailing list