]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-conf.c
networkd: clean up DUID code a bit
[thirdparty/systemd.git] / src / network / networkd-conf.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2014 Vinay Kulkarni <kulkarniv@vmware.com>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <ctype.h>
21
22 #include "conf-parser.h"
23 #include "def.h"
24 #include "dhcp-identifier.h"
25 #include "hexdecoct.h"
26 #include "networkd-conf.h"
27 #include "string-table.h"
28
29 int manager_parse_config_file(Manager *m) {
30 assert(m);
31
32 return config_parse_many(PKGSYSCONFDIR "/networkd.conf",
33 CONF_PATHS_NULSTR("systemd/networkd.conf.d"),
34 "DHCP\0",
35 config_item_perf_lookup, networkd_gperf_lookup,
36 false, m);
37 }
38
39 static const char* const duid_type_table[_DUID_TYPE_MAX] = {
40 [DUID_TYPE_RAW] = "raw",
41 [DUID_TYPE_LLT] = "link-layer-time",
42 [DUID_TYPE_EN] = "vendor",
43 [DUID_TYPE_LL] = "link-layer",
44 [DUID_TYPE_UUID] = "uuid"
45 };
46 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType);
47 DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type");
48
49 int config_parse_duid_rawdata(
50 const char *unit,
51 const char *filename,
52 unsigned line,
53 const char *section,
54 unsigned section_line,
55 const char *lvalue,
56 int ltype,
57 const char *rvalue,
58 void *data,
59 void *userdata) {
60
61 int r;
62 char *cbyte;
63 const char *pduid = rvalue;
64 Manager *m = userdata;
65 Network *n = userdata;
66 DUIDType duidtype;
67 uint16_t dhcp_duid_type = 0;
68 uint8_t dhcp_duid[MAX_DUID_LEN];
69 size_t len, count = 0, duid_start_offset = 0, dhcp_duid_len = 0;
70
71 assert(filename);
72 assert(lvalue);
73 assert(rvalue);
74 assert(userdata);
75
76 duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type : n->duid_type;
77
78 if (duidtype == _DUID_TYPE_INVALID)
79 duidtype = DUID_TYPE_RAW;
80
81 switch (duidtype) {
82
83 case DUID_TYPE_LLT:
84 /* RawData contains DUID-LLT link-layer address (offset 6) */
85 duid_start_offset = 6;
86 break;
87
88 case DUID_TYPE_EN:
89 /* RawData contains DUID-EN identifier (offset 4) */
90 duid_start_offset = 4;
91 break;
92
93 case DUID_TYPE_LL:
94 /* RawData contains DUID-LL link-layer address (offset 2) */
95 duid_start_offset = 2;
96 break;
97
98 case DUID_TYPE_UUID:
99 /* RawData specifies UUID (offset 0) - fall thru */
100
101 case DUID_TYPE_RAW:
102 /* First two bytes of RawData is DUID Type - fall thru */
103
104 default:
105 break;
106 }
107
108 if (duidtype != DUID_TYPE_RAW)
109 dhcp_duid_type = (uint16_t) duidtype;
110
111 /* RawData contains DUID in format " NN:NN:NN... " */
112 for (;;) {
113 int n1, n2;
114 uint32_t byte;
115
116 r = extract_first_word(&pduid, &cbyte, ":", 0);
117 if (r < 0) {
118 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue);
119 return 0;
120 }
121 if (r == 0)
122 break;
123 if (duid_start_offset + dhcp_duid_len >= MAX_DUID_LEN) {
124 log_syntax(unit, LOG_ERR, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue);
125 return 0;
126 }
127
128 len = strlen(cbyte);
129 if (len != 1 && len != 2) {
130 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue);
131 return 0;
132 }
133 n1 = unhexchar(cbyte[0]);
134 if (len == 2)
135 n2 = unhexchar(cbyte[1]);
136 else
137 n2 = 0;
138
139 if (n1 < 0 || n2 < 0) {
140 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue);
141 return 0;
142 }
143
144 byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2;
145
146 /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */
147 if (duidtype == DUID_TYPE_RAW && count < 2) {
148 dhcp_duid_type |= (byte << (8 * (1 - count)));
149 count++;
150 continue;
151 }
152
153 dhcp_duid[duid_start_offset + dhcp_duid_len] = byte;
154 dhcp_duid_len++;
155 }
156
157 if (ltype == DUID_CONFIG_SOURCE_GLOBAL) {
158 m->duid_type = duidtype;
159 m->dhcp_duid_type = dhcp_duid_type;
160 m->dhcp_duid_len = dhcp_duid_len;
161 memcpy(&m->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len);
162 } else {
163 /* DUID_CONFIG_SOURCE_NETWORK */
164 n->duid_type = duidtype;
165 n->dhcp_duid_type = dhcp_duid_type;
166 n->dhcp_duid_len = dhcp_duid_len;
167 memcpy(&n->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len);
168 }
169
170 return 0;
171 }