]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address.c
rtnl: replace message_append by typesafe versions
[thirdparty/systemd.git] / src / network / networkd-address.c
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
31 int address_new(Network *network, unsigned section, Address **ret) {
32 _cleanup_address_free_ Address *address = NULL;
33
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
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
53 if (section) {
54 address->section = section;
55 hashmap_put(network->addresses_by_section, &address->section, address);
56 }
57
58 *ret = address;
59 address = NULL;
60
61 return 0;
62 }
63
64 void address_free(Address *address) {
65 if (!address)
66 return;
67
68 LIST_REMOVE(addresses, address->network->addresses, address);
69
70 if (address->section)
71 hashmap_remove(address->network->addresses_by_section,
72 &address->section);
73
74 free(address);
75 }
76
77 int address_configure(Address *address, Link *link,
78 sd_rtnl_message_handler_t callback) {
79 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
80 int r;
81
82 assert(address);
83 assert(address->family == AF_INET || address->family == AF_INET6);
84 assert(link);
85 assert(link->ifindex > 0);
86 assert(link->manager);
87 assert(link->manager->rtnl);
88
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
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);
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
111 broadcast.s_addr = address->in_addr.in.s_addr | address->netmask.s_addr;
112
113 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &broadcast);
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) {
122 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
123 if (r < 0) {
124 log_error("Could not append IFA_LABEL attribute: %s",
125 strerror(-r));
126 return r;
127 }
128 }
129
130 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
131 if (r < 0) {
132 log_error("Could not send rtnetlink message: %s", strerror(-r));
133 return r;
134 }
135
136 return 0;
137 }
138
139 int config_parse_address(const char *unit,
140 const char *filename,
141 unsigned line,
142 const char *section,
143 unsigned section_line,
144 const char *lvalue,
145 int ltype,
146 const char *rvalue,
147 void *data,
148 void *userdata) {
149 Network *network = userdata;
150 _cleanup_address_free_ Address *n = NULL;
151 _cleanup_free_ char *address = NULL;
152 const char *e;
153 int r;
154
155 assert(filename);
156 assert(section);
157 assert(lvalue);
158 assert(rvalue);
159 assert(data);
160
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
167 r = address_new(network, section_line, &n);
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;
186 n->netmask.s_addr = htonl(0xfffffffflu >> n->prefixlen);
187
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 }
208
209 int 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;
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 }