]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
rtnl: replace message_append by typesafe versions
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <net/if.h>
23
24#include "networkd.h"
25
26#include "utf8.h"
27#include "util.h"
28#include "conf-parser.h"
29#include "net-util.h"
30
6ae115c1 31int address_new(Network *network, unsigned section, Address **ret) {
f579559b
TG
32 _cleanup_address_free_ Address *address = NULL;
33
6ae115c1
TG
34 if (section) {
35 uint64_t key = section;
36 address = hashmap_get(network->addresses_by_section, &key);
37 if (address) {
38 *ret = address;
39 address = NULL;
40
41 return 0;
42 }
43 }
44
f579559b
TG
45 address = new0(Address, 1);
46 if (!address)
47 return -ENOMEM;
48
49 address->network = network;
50
51 LIST_PREPEND(addresses, network->addresses, address);
52
6ae115c1
TG
53 if (section) {
54 address->section = section;
55 hashmap_put(network->addresses_by_section, &address->section, address);
56 }
57
f579559b
TG
58 *ret = address;
59 address = NULL;
60
61 return 0;
62}
63
64void address_free(Address *address) {
65 if (!address)
66 return;
67
68 LIST_REMOVE(addresses, address->network->addresses, address);
69
6ae115c1
TG
70 if (address->section)
71 hashmap_remove(address->network->addresses_by_section,
72 &address->section);
73
f579559b
TG
74 free(address);
75}
76
f882c247
TG
77int address_configure(Address *address, Link *link,
78 sd_rtnl_message_handler_t callback) {
f579559b
TG
79 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
80 int r;
81
c166a070
TG
82 assert(address);
83 assert(address->family == AF_INET || address->family == AF_INET6);
84 assert(link);
85 assert(link->ifindex > 0);
f882c247 86 assert(link->manager);
c166a070 87 assert(link->manager->rtnl);
f882c247 88
f579559b
TG
89 r = sd_rtnl_message_addr_new(RTM_NEWADDR, link->ifindex,
90 address->family, address->prefixlen,
91 IFA_F_PERMANENT, RT_SCOPE_UNIVERSE, &req);
92 if (r < 0) {
93 log_error("Could not allocate RTM_NEWADDR message: %s",
94 strerror(-r));
95 return r;
96 }
97
0a0dc69b
TG
98 if (address->family == AF_INET)
99 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
100 else if (address->family == AF_INET6)
101 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
f579559b
TG
102 if (r < 0) {
103 log_error("Could not append IFA_LOCAL attribute: %s",
104 strerror(-r));
105 return r;
106 }
107
108 if (address->family == AF_INET) {
109 struct in_addr broadcast;
110
8cd11a0f 111 broadcast.s_addr = address->in_addr.in.s_addr | address->netmask.s_addr;
f579559b 112
0a0dc69b 113 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &broadcast);
f579559b
TG
114 if (r < 0) {
115 log_error("Could not append IFA_BROADCAST attribute: %s",
116 strerror(-r));
117 return r;
118 }
119 }
120
121 if (address->label) {
0a0dc69b 122 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
f579559b
TG
123 if (r < 0) {
124 log_error("Could not append IFA_LABEL attribute: %s",
125 strerror(-r));
126 return r;
127 }
128 }
129
f882c247 130 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
f579559b 131 if (r < 0) {
f882c247
TG
132 log_error("Could not send rtnetlink message: %s", strerror(-r));
133 return r;
f579559b
TG
134 }
135
f579559b
TG
136 return 0;
137}
138
139int config_parse_address(const char *unit,
140 const char *filename,
141 unsigned line,
142 const char *section,
71a61510 143 unsigned section_line,
f579559b
TG
144 const char *lvalue,
145 int ltype,
146 const char *rvalue,
147 void *data,
148 void *userdata) {
6ae115c1 149 Network *network = userdata;
f579559b
TG
150 _cleanup_address_free_ Address *n = NULL;
151 _cleanup_free_ char *address = NULL;
152 const char *e;
153 int r;
154
155 assert(filename);
6ae115c1 156 assert(section);
f579559b
TG
157 assert(lvalue);
158 assert(rvalue);
159 assert(data);
160
92fe133a
TG
161 if (streq(section, "Network")) {
162 /* we are not in an Address section, so treat
163 * this as the special '0' section */
164 section_line = 0;
165 }
166
6ae115c1 167 r = address_new(network, section_line, &n);
f579559b
TG
168 if (r < 0)
169 return r;
170
171 /* Address=address/prefixlen */
172
173 /* prefixlen */
174 e = strchr(rvalue, '/');
175 if (e) {
176 unsigned i;
177 r = safe_atou(e + 1, &i);
178 if (r < 0) {
179 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
180 "Interface prefix length is invalid, "
181 "ignoring assignment: %s", e + 1);
182 return 0;
183 }
184
185 n->prefixlen = (unsigned char) i;
8cd11a0f
TG
186 n->netmask.s_addr = htonl(0xfffffffflu >> n->prefixlen);
187
f579559b
TG
188 address = strndup(rvalue, e - rvalue);
189 if (!address)
190 return log_oom();
191 } else {
192 address = strdup(rvalue);
193 if (!address)
194 return log_oom();
195 }
196
197 r = net_parse_inaddr(address, &n->family, &n->in_addr);
198 if (r < 0) {
199 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
200 "Address is invalid, ignoring assignment: %s", address);
201 return 0;
202 }
203
204 n = NULL;
205
206 return 0;
207}
6ae115c1
TG
208
209int config_parse_label(const char *unit,
210 const char *filename,
211 unsigned line,
212 const char *section,
213 unsigned section_line,
214 const char *lvalue,
215 int ltype,
216 const char *rvalue,
217 void *data,
218 void *userdata) {
219 Network *network = userdata;
220 _cleanup_address_free_ Address *n = NULL;
6ae115c1
TG
221 char *label;
222 int r;
223
224 assert(filename);
225 assert(section);
226 assert(lvalue);
227 assert(rvalue);
228 assert(data);
229
230 r = address_new(network, section_line, &n);
231 if (r < 0)
232 return r;
233
234 label = strdup(rvalue);
235 if (!label)
236 return log_oom();
237
238 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
239 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
240 "Interface label is not ASCII clean or is too"
241 " long, ignoring assignment: %s", rvalue);
242 free(label);
243 return 0;
244 }
245
246 free(n->label);
247 if (*label)
248 n->label = label;
249 else {
250 free(label);
251 n->label = NULL;
252 }
253
254 n = NULL;
255
256 return 0;
257}