]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
networkd: dhcp server Support Vendor specific 43
authorSusant Sahani <ssahani@vmware.com>
Fri, 20 Sep 2019 02:22:17 +0000 (04:22 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 31 Oct 2019 00:03:43 +0000 (09:03 +0900)
Implementes https://tools.ietf.org/html/rfc2132

```
[DHCPServer]
SendRawOption=26:uint32:1400
SendRawOption=23:uint8:10

```
Frame 448: 350 bytes on wire (2800 bits), 350 bytes captured (2800 bits) on interface 0
Linux cooked capture
Internet Protocol Version 4, Src: 192.168.5.1, Dst: 192.168.5.11
User Datagram Protocol, Src Port: 67, Dst Port: 68
Dynamic Host Configuration Protocol (ACK)
    Message type: Boot Reply (2)
    Hardware type: Ethernet (0x01)
    Hardware address length: 6
    Hops: 0
    Transaction ID: 0x71f8de9d
    Seconds elapsed: 0
    Bootp flags: 0x0000 (Unicast)
    Client IP address: 0.0.0.0
    Your (client) IP address: 192.168.5.11
    Next server IP address: 0.0.0.0
    Relay agent IP address: 0.0.0.0
    Client MAC address: 1e:04:f8:b8:2f:d4 (1e:04:f8:b8:2f:d4)
    Client hardware address padding: 00000000000000000000
    Server host name not given
    Boot file name not given
    Magic cookie: DHCP
    Option: (53) DHCP Message Type (ACK)
        Length: 1
        DHCP: ACK (5)
    Option: (51) IP Address Lease Time
        Length: 4
        IP Address Lease Time: (3600s) 1 hour
    Option: (1) Subnet Mask (255.255.255.0)
        Length: 4
        Subnet Mask: 255.255.255.0
    Option: (3) Router
        Length: 4
        Router: 192.168.5.1
    Option: (6) Domain Name Server
        Length: 4
        Domain Name Server: 192.168.5.1
    Option: (42) Network Time Protocol Servers
        Length: 4
        Network Time Protocol Server: 192.168.5.1
    Option: (101) TCode
        Length: 13
        TZ TCode: Europe/Berlin
    Option: (43) Vendor-Specific Information
        Length: 9
        Value: 1701311a0431343030
    Option: (54) DHCP Server Identifier (192.168.5.1)
        Length: 4
        DHCP Server Identifier: 192.168.5.1
    Option: (255) End
        Option End: 255

```

man/systemd.network.xml
src/libsystemd-network/dhcp-option.c
src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/sd-dhcp-server.c
src/network/networkd-dhcp-server.c
src/network/networkd-dhcp-server.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/systemd/sd-dhcp-server.h
test/fuzz/fuzz-network-parser/directives.network

index 538f4b8e7b37624ac792b08a9521820b05226a81..0d49bf95895457b9c2749df94d8f806352947fa8 100644 (file)
         <filename>/etc/localtime</filename> symlink.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+          <term><varname>SendRawOption=</varname></term>
+          <listitem>
+            <para>Send a raw option with value via DHCPv4 server. Takes a DHCP option, data type and data
+            (option:type:value). The option ranges [1-254]. The type takes one of <literal>uint8</literal>,
+            <literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, or <literal>string</literal>.
+            Special characters in the data string may be escaped using
+            <ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
+            escapes</ulink>. This option can be specified multiple times. If an empty string is specified, then all
+            options specified earlier are cleared. Defaults to unset.</para>
+          </listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
index d2f1f5d806e3fdaea95a2185a3428a2938884318..78baeb73335c13adfb6bac8f526484aacf3f3139 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "alloc-util.h"
 #include "dhcp-internal.h"
+#include "dhcp-server-internal.h"
 #include "memory-util.h"
 #include "strv.h"
 #include "utf8.h"
@@ -77,6 +78,32 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
                 *offset += 3 + optlen;
 
                 break;
+        case SD_DHCP_OPTION_VENDOR_SPECIFIC: {
+                OrderedHashmap *s = (OrderedHashmap *) optval;
+                struct sd_dhcp_raw_option *p;
+                size_t l = 0;
+                Iterator i;
+
+                ORDERED_HASHMAP_FOREACH(p, s, i)
+                        l += p->length + 2;
+
+                if (*offset + l + 2 > size)
+                        return -ENOBUFS;
+
+                options[*offset] = code;
+                options[*offset + 1] = l;
+
+                *offset += 2;
+
+                ORDERED_HASHMAP_FOREACH(p, s, i) {
+                        options[*offset] = p->type;
+                        options[*offset + 1] = p->length;
+                        memcpy(&options[*offset + 2], p->data, p->length);
+                        *offset += 2 + p->length;
+                }
+
+                break;
+        }
         default:
                 if (*offset + 2 + optlen > size)
                         return -ENOBUFS;
index 0a64082cd192c9fbe6cbb371d3cd05b7e38d16b1..e537d9e6227e0d5659f7e114975c9ac6aad1233e 100644 (file)
 #include "log.h"
 #include "time-util.h"
 
+typedef enum DHCPRawOption {
+        DHCP_RAW_OPTION_DATA_UINT8,
+        DHCP_RAW_OPTION_DATA_UINT16,
+        DHCP_RAW_OPTION_DATA_UINT32,
+        DHCP_RAW_OPTION_DATA_STRING,
+        DHCP_RAW_OPTION_DATA_IPV4ADDRESS,
+        _DHCP_RAW_OPTION_DATA_MAX,
+        _DHCP_RAW_OPTION_DATA_INVALID,
+} DHCPRawOption;
+
 typedef struct DHCPClientId {
         size_t length;
         void *data;
@@ -27,6 +37,15 @@ typedef struct DHCPLease {
         usec_t expiration;
 } DHCPLease;
 
+struct sd_dhcp_raw_option {
+        unsigned n_ref;
+
+        uint8_t type;
+        uint8_t length;
+
+        void *data;
+};
+
 struct sd_dhcp_server {
         unsigned n_ref;
 
@@ -48,6 +67,8 @@ struct sd_dhcp_server {
         struct in_addr *ntp, *dns, *sip;
         unsigned n_ntp, n_dns, n_sip;
 
+        OrderedHashmap *raw_option;
+
         bool emit_router;
 
         Hashmap *leases_by_client_id;
index bba82c21dd7f70a503a8777fc45ac2346f541019..9e1a7698fca701cd82b900b10f8ecb1bdd807b85 100644 (file)
@@ -127,6 +127,46 @@ int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(dhcp_lease_hash_ops, DHCPClientId, client_id_hash_func, client_id_compare_func,
                                               DHCPLease, dhcp_lease_free);
 
+static sd_dhcp_raw_option* raw_option_free(sd_dhcp_raw_option *i) {
+        if (!i)
+                return NULL;
+
+        free(i->data);
+        return mfree(i);
+}
+
+_public_ int sd_dhcp_raw_option_new(uint8_t type, char *data, size_t length, sd_dhcp_raw_option **ret) {
+        sd_dhcp_raw_option *p;
+
+        assert_return(ret, -EINVAL);
+
+        p = new(sd_dhcp_raw_option, 1);
+        if (!p)
+                return -ENOMEM;
+
+        *p = (sd_dhcp_raw_option) {
+                  .n_ref = 1,
+                  .data = memdup(data, length),
+                  .length = length,
+                  .type = type,
+        };
+
+        if (!p->data)
+                return -ENOMEM;
+
+        *ret = p;
+        return 0;
+}
+
+DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_raw_option, sd_dhcp_raw_option, raw_option_free);
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+                dhcp_raw_options_hash_ops,
+                void,
+                trivial_hash_func,
+                trivial_compare_func,
+                sd_dhcp_raw_option,
+                sd_dhcp_raw_option_unref);
+
 static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
         assert(server);
 
@@ -143,6 +183,8 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
 
         hashmap_free(server->leases_by_client_id);
 
+        ordered_hashmap_free(server->raw_option);
+
         free(server->bound_leases);
         return mfree(server);
 }
@@ -452,8 +494,8 @@ static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
                            be32_t address) {
         _cleanup_free_ DHCPPacket *packet = NULL;
-        size_t offset;
         be32_t lease_time;
+        size_t offset;
         int r;
 
         r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
@@ -517,6 +559,15 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
                         return r;
         }
 
+        if (!ordered_hashmap_isempty(server->raw_option)) {
+                r = dhcp_option_append(
+                                &packet->dhcp, req->max_optlen, &offset, 0,
+                                SD_DHCP_OPTION_VENDOR_SPECIFIC,
+                                ordered_hashmap_size(server->raw_option), server->raw_option);
+                if (r < 0)
+                        return r;
+        }
+
         r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
         if (r < 0)
                 return r;
@@ -1170,3 +1221,22 @@ int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) {
 
         return 1;
 }
+
+int sd_dhcp_server_add_raw_option(sd_dhcp_server *server, sd_dhcp_raw_option *v) {
+        int r;
+
+        assert_return(server, -EINVAL);
+        assert_return(v, -EINVAL);
+
+        r = ordered_hashmap_ensure_allocated(&server->raw_option, &dhcp_raw_options_hash_ops);
+        if (r < 0)
+                return -ENOMEM;
+
+        r = ordered_hashmap_put(server->raw_option, v, v);
+        if (r < 0)
+                return r;
+
+        sd_dhcp_raw_option_ref(v);
+
+        return 1;
+}
index efb82d7e9a6f0b259fbcfd50d100b6e3be29e18d..77eb46341cc286fd1e83cd291776773a5667cf28 100644 (file)
@@ -2,11 +2,15 @@
 
 #include "sd-dhcp-server.h"
 
+#include "escape.h"
 #include "networkd-dhcp-server.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-network.h"
+#include "parse-util.h"
 #include "strv.h"
+#include "string-table.h"
+#include "string-util.h"
 
 static Address* link_find_dhcp_server_address(Link *link) {
         Address *address;
@@ -187,9 +191,11 @@ static int link_push_uplink_sip_to_dhcp_server(Link *link, sd_dhcp_server *s) {
 }
 
 int dhcp4_server_configure(Link *link) {
-        Address *address;
-        Link *uplink = NULL;
         bool acquired_uplink = false;
+        sd_dhcp_raw_option *p;
+        Link *uplink = NULL;
+        Address *address;
+        Iterator i;
         int r;
 
         address = link_find_dhcp_server_address(link);
@@ -298,6 +304,15 @@ int dhcp4_server_configure(Link *link) {
                 if (r < 0)
                         return r;
         }
+
+        ORDERED_HASHMAP_FOREACH(p, link->network->dhcp_server_raw_options, i) {
+                r = sd_dhcp_server_add_raw_option(link->dhcp_server, p);
+                if (r == -EEXIST)
+                        continue;
+                if (r < 0)
+                        return r;
+        }
+
         if (!sd_dhcp_server_is_running(link->dhcp_server)) {
                 r = sd_dhcp_server_start(link->dhcp_server);
                 if (r < 0)
@@ -464,3 +479,178 @@ int config_parse_dhcp_server_sip(
                 n->dhcp_server_sip = m;
         }
 }
+
+static const char * const dhcp_raw_option_data_type_table[_DHCP_RAW_OPTION_DATA_MAX] = {
+        [DHCP_RAW_OPTION_DATA_UINT8]      = "uint8",
+        [DHCP_RAW_OPTION_DATA_UINT16]     = "uint16",
+        [DHCP_RAW_OPTION_DATA_UINT32]     = "uint32",
+        [DHCP_RAW_OPTION_DATA_STRING]     = "string",
+        [DHCP_RAW_OPTION_DATA_IPV4ADDRESS] = "ipv4address",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(dhcp_raw_option_data_type, DHCPRawOption);
+
+int config_parse_dhcp_server_raw_option_data(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        _cleanup_(sd_dhcp_raw_option_unrefp) sd_dhcp_raw_option *opt = NULL, *old = NULL;
+        _cleanup_free_ char *word = NULL, *q = NULL;
+        union in_addr_union addr;
+        Network *network = data;
+        uint16_t uint16_data;
+        uint32_t uint32_data;
+        uint8_t uint8_data;
+        DHCPRawOption type;
+        const char *p;
+        void *udata;
+        ssize_t sz;
+        uint8_t u;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (isempty(rvalue)) {
+                network->dhcp_server_raw_options = ordered_hashmap_free(network->dhcp_server_raw_options);
+                return 0;
+        }
+
+        p = rvalue;
+        r = extract_first_word(&p, &word, ":", 0);
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r <= 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Invalid DHCP server send raw option, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        r = safe_atou8(word, &u);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse  DHCP server send raw option type, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+        if (u < 1 || u >= 255) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Invalid DHCP server send raw option, valid range is 1-254, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        free(word);
+
+        r = extract_first_word(&p, &word, ":", 0);
+        if (r == -ENOMEM)
+                return log_oom();
+        if (r <= 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Invalid DHCP server send raw option, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        r = dhcp_raw_option_data_type_from_string(word);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Invalid DHCP server send data type, ignoring assignment: %s", p);
+                return 0;
+        }
+
+        type = r;
+        switch(type) {
+        case DHCP_RAW_OPTION_DATA_UINT8:{
+                r = safe_atou8(p, &uint8_data);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse DHCPv4 vendor specific uint8 data, ignoring assignment: %s", p);
+                        return 0;
+                }
+
+                udata = &uint8_data;
+                sz = sizeof(uint8_t);
+                break;
+        }
+        case DHCP_RAW_OPTION_DATA_UINT16:{
+                r = safe_atou16(p, &uint16_data);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse DHCPv4 vendor specific uint16 data, ignoring assignment: %s", p);
+                        return 0;
+                }
+
+                udata = &uint16_data;
+                sz = sizeof(uint16_t);
+                break;
+        }
+        case DHCP_RAW_OPTION_DATA_UINT32: {
+                r = safe_atou32(p, &uint32_data);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse DHCPv4 vendor specific uint32 data, ignoring assignment: %s", p);
+                        return 0;
+                }
+
+                udata = &uint32_data;
+                sz = sizeof(uint32_t);
+
+                break;
+        }
+        case DHCP_RAW_OPTION_DATA_IPV4ADDRESS: {
+                r = in_addr_from_string(AF_INET, p, &addr);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse DHCPv4 vendor specific ipv4address data, ignoring assignment: %s", p);
+                        return 0;
+                }
+
+                udata = &addr.in;
+                sz = sizeof(addr.in.s_addr);
+                break;
+        }
+        case DHCP_RAW_OPTION_DATA_STRING:
+                sz = cunescape(p, 0, &q);
+                if (sz < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, sz,
+                                   "Failed to decode option data, ignoring assignment: %s", p);
+                }
+
+                udata = q;
+                break;
+        default:
+                return -EINVAL;
+        }
+
+        r = sd_dhcp_raw_option_new(u, udata, sz, &opt);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to store DHCP send raw option '%s', ignoring assignment: %m", rvalue);
+                return 0;
+        }
+
+        r = ordered_hashmap_ensure_allocated(&network->dhcp_server_raw_options, &dhcp_raw_options_hash_ops);
+        if (r < 0)
+                return log_oom();
+
+        /* Overwrite existing option */
+        old = ordered_hashmap_remove(network->dhcp_server_raw_options, UINT_TO_PTR(u));
+        r = ordered_hashmap_put(network->dhcp_server_raw_options, UINT_TO_PTR(u), opt);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to store DHCP server send raw option '%s'", rvalue);
+                return 0;
+        }
+
+        TAKE_PTR(opt);
+
+        return 0;
+}
index 7c12538096fb9c901e8cc02be6419c939fe3f147..c30162dd5b6a79da160264058a57344b036ef3e5 100644 (file)
@@ -2,11 +2,27 @@
 #pragma once
 
 #include "conf-parser.h"
+#include "networkd-link.h"
+#include "networkd-util.h"
 
 typedef struct Link Link;
 
+typedef enum DHCPRawOption {
+        DHCP_RAW_OPTION_DATA_UINT8,
+        DHCP_RAW_OPTION_DATA_UINT16,
+        DHCP_RAW_OPTION_DATA_UINT32,
+        DHCP_RAW_OPTION_DATA_STRING,
+        DHCP_RAW_OPTION_DATA_IPV4ADDRESS,
+        _DHCP_RAW_OPTION_DATA_MAX,
+        _DHCP_RAW_OPTION_DATA_INVALID,
+} DHCPRawOption;
+
+const char *dhcp_raw_option_data_type_to_string(DHCPRawOption d) _const_;
+DHCPRawOption dhcp_raw_option_data_type_from_string(const char *d) _pure_;
+
 int dhcp4_server_configure(Link *link);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_dns);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_ntp);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_sip);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_raw_option_data);
index 446ba9f084b962d6105477ec82763c9f50d4e2d0..9f53385602782d62f290df483c46673ba11b6f86 100644 (file)
@@ -200,6 +200,7 @@ DHCPServer.EmitTimezone,                config_parse_bool,
 DHCPServer.Timezone,                    config_parse_timezone,                           0,                             offsetof(Network, dhcp_server_timezone)
 DHCPServer.PoolOffset,                  config_parse_uint32,                             0,                             offsetof(Network, dhcp_server_pool_offset)
 DHCPServer.PoolSize,                    config_parse_uint32,                             0,                             offsetof(Network, dhcp_server_pool_size)
+DHCPServer.SendRawOption,               config_parse_dhcp_server_raw_option_data,        0,                             0
 Bridge.Cost,                            config_parse_uint32,                             0,                             offsetof(Network, cost)
 Bridge.UseBPDU,                         config_parse_tristate,                           0,                             offsetof(Network, use_bpdu)
 Bridge.HairPin,                         config_parse_tristate,                           0,                             offsetof(Network, hairpin)
index 0956d2a9b797227bd203f23f81889b6517aadf6e..90d86f35a9542c6b9d49ff5f831251ab6c640276 100644 (file)
@@ -11,6 +11,7 @@
 #include "fd-util.h"
 #include "hostname-util.h"
 #include "in-addr-util.h"
+#include "networkd-dhcp-server.h"
 #include "network-internal.h"
 #include "networkd-manager.h"
 #include "networkd-network.h"
@@ -144,14 +145,14 @@ static int network_resolve_stacked_netdevs(Network *network) {
 }
 
 int network_verify(Network *network) {
-        Address *address, *address_next;
-        Route *route, *route_next;
-        FdbEntry *fdb, *fdb_next;
+        RoutingPolicyRule *rule, *rule_next;
         Neighbor *neighbor, *neighbor_next;
         AddressLabel *label, *label_next;
-        Prefix *prefix, *prefix_next;
-        RoutingPolicyRule *rule, *rule_next;
         NextHop *nexthop, *nextnop_next;
+        Address *address, *address_next;
+        Prefix *prefix, *prefix_next;
+        Route *route, *route_next;
+        FdbEntry *fdb, *fdb_next;
 
         assert(network);
         assert(network->filename);
@@ -680,6 +681,7 @@ static Network *network_free(Network *network) {
         set_free_free(network->dnssec_negative_trust_anchors);
 
         ordered_hashmap_free(network->dhcp_send_options);
+        ordered_hashmap_free(network->dhcp_server_raw_options);
 
         return mfree(network);
 }
index 0d4559774cbfcfbb45264c24386081f1c2ccccff..9258bf55f74826baa5c5251fa4b8582878c16ed2 100644 (file)
@@ -16,6 +16,7 @@
 #include "networkd-brvlan.h"
 #include "networkd-dhcp-common.h"
 #include "networkd-dhcp4.h"
+#include "networkd-dhcp-server.h"
 #include "networkd-fdb.h"
 #include "networkd-ipv6-proxy-ndp.h"
 #include "networkd-lldp-rx.h"
@@ -114,6 +115,7 @@ struct Network {
         Set *dhcp_black_listed_ip;
         Set *dhcp_request_options;
         OrderedHashmap *dhcp_send_options;
+        OrderedHashmap *dhcp_server_raw_options;
 
         /* DHCPv6 Client support*/
         bool dhcp6_use_dns;
index 2252a4aa88d016922139664744b5606d53255515..ba1bc4458a5e1db738234fb3734f0284ebd39cd1 100644 (file)
 
 _SD_BEGIN_DECLARATIONS;
 
+extern const struct hash_ops dhcp_raw_options_hash_ops;
+
 typedef struct sd_dhcp_server sd_dhcp_server;
+typedef struct sd_dhcp_raw_option sd_dhcp_raw_option;
 
 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex);
 
 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server);
 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server);
 
+int sd_dhcp_raw_option_new(uint8_t type, char *data, size_t lengt, sd_dhcp_raw_option **ret);
+sd_dhcp_raw_option *sd_dhcp_raw_option_ref(sd_dhcp_raw_option *ra);
+sd_dhcp_raw_option *sd_dhcp_raw_option_unref(sd_dhcp_raw_option *ra);
+
 int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int64_t priority);
 int sd_dhcp_server_detach_event(sd_dhcp_server *client);
 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client);
@@ -51,12 +58,15 @@ int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], u
 int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], unsigned n);
 int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled);
 
+int sd_dhcp_server_add_raw_option(sd_dhcp_server *server, sd_dhcp_raw_option *v);
+
 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t);
 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t);
 
 int sd_dhcp_server_forcerenew(sd_dhcp_server *server);
 
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_server, sd_dhcp_server_unref);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_raw_option, sd_dhcp_raw_option_unref);
 
 _SD_END_DECLARATIONS;
 
index f01a20118bd5955af26fe2e551904bb911c9eb55..3469dd443ec348be3b728b0bcca42e64136d7dad 100644 (file)
@@ -259,6 +259,7 @@ MaxLeaseTimeSec=
 DefaultLeaseTimeSec=
 EmitTimezone=
 DNS=
+SendRawOption=
 [NextHop]
 Id=
 Gateway=