dhcp-option.c revision 2688ef60de061bf188c1153c58fb41a78919b97e
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/***
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright (C) 2013 Intel Corporation. All rights reserved.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering***/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <stdint.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <string.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <stdio.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering#include "dhcp-internal.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dhcp_option_append(uint8_t options[], size_t size, size_t *offset,
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering uint8_t code, size_t optlen, const void *optval) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering assert(options);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(offset);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (code != DHCP_OPTION_END)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* always make sure there is space for an END option */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size --;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering switch (code) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt case DHCP_OPTION_PAD:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering case DHCP_OPTION_END:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (size - *offset < 1)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOBUFS;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering options[*offset] = code;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *offset += 1;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering break;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
af49ca27ffd790d78dbbb465b978266dfd5c93daLennart Poettering default:
ad6c04756115809d615dede330213d73edf732a8Lennart Poettering if (size - *offset < optlen + 2)
ad6c04756115809d615dede330213d73edf732a8Lennart Poettering return -ENOBUFS;
6955a3ba9dc5d36487724878333a5745987e6656Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(optval);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering options[*offset] = code;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering options[*offset + 1] = optlen;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering memcpy(&options[*offset + 2], optval, optlen);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *offset += optlen + 2;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering break;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poetteringstatic int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering uint8_t *message_type, dhcp_option_cb_t cb,
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering void *user_data) {
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering uint8_t code, len;
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering size_t offset = 0;
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering while (offset < buflen) {
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering switch (options[offset]) {
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering case DHCP_OPTION_PAD:
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering offset++;
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering break;
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering case DHCP_OPTION_END:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering case DHCP_OPTION_MESSAGE_TYPE:
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering if (buflen < offset + 3)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return -ENOBUFS;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering len = options[++offset];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (len != 1)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -EINVAL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (message_type)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *message_type = options[++offset];
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering else
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering offset++;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack offset++;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering break;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering case DHCP_OPTION_OVERLOAD:
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (buflen < offset + 3)
97e5d693c04e50605d438af1c8a965fd2963bbe9Lennart Poettering return -ENOBUFS;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering len = options[++offset];
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (len != 1)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -EINVAL;
dfc1091b2f5f21f69e0aa6d3c4536b8990d4b100Lennart Poettering
dfc1091b2f5f21f69e0aa6d3c4536b8990d4b100Lennart Poettering if (overload)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering *overload = options[++offset];
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering else
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering offset++;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering offset++;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering break;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
dfc1091b2f5f21f69e0aa6d3c4536b8990d4b100Lennart Poettering default:
af49ca27ffd790d78dbbb465b978266dfd5c93daLennart Poettering if (buflen < offset + 3)
af49ca27ffd790d78dbbb465b978266dfd5c93daLennart Poettering return -ENOBUFS;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering code = options[offset];
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering len = options[++offset];
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (buflen < ++offset + len)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -EINVAL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (cb)
dfc1091b2f5f21f69e0aa6d3c4536b8990d4b100Lennart Poettering cb(code, len, &options[offset], user_data);
af49ca27ffd790d78dbbb465b978266dfd5c93daLennart Poettering
af49ca27ffd790d78dbbb465b978266dfd5c93daLennart Poettering offset += len;
db97a66aa69925f7403ba3c433e86320d136567dLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering break;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering }
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (offset < buflen)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return -EINVAL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack return 0;
dfc1091b2f5f21f69e0aa6d3c4536b8990d4b100Lennart Poettering}
af49ca27ffd790d78dbbb465b978266dfd5c93daLennart Poettering
af49ca27ffd790d78dbbb465b978266dfd5c93daLennart Poetteringint dhcp_option_parse(DHCPMessage *message, size_t len,
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack dhcp_option_cb_t cb, void *user_data) {
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack uint8_t overload = 0;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack uint8_t message_type = 0;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack int r;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack if (!message)
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack return -EINVAL;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack
dfc1091b2f5f21f69e0aa6d3c4536b8990d4b100Lennart Poettering if (len < sizeof(DHCPMessage))
af49ca27ffd790d78dbbb465b978266dfd5c93daLennart Poettering return -EINVAL;
af49ca27ffd790d78dbbb465b978266dfd5c93daLennart Poettering
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack len -= sizeof(DHCPMessage);
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack r = parse_options(message->options, len, &overload, &message_type,
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack cb, user_data);
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack if (r < 0)
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack return r;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (overload & DHCP_OVERLOAD_FILE) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = parse_options(message->file, sizeof(message->file),
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering NULL, &message_type, cb, user_data);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return r;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (overload & DHCP_OVERLOAD_SNAME) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = parse_options(message->sname, sizeof(message->sname),
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen NULL, &message_type, cb, user_data);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (message_type)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return message_type;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return -ENOMSG;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering