chiark / gitweb /
dhcp: Add option append tests
[elogind.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         r = sd_rtnl_message_append(req, IFA_LOCAL, &address->in_addr);
99         if (r < 0) {
100                 log_error("Could not append IFA_LOCAL attribute: %s",
101                           strerror(-r));
102                 return r;
103         }
104
105         if (address->family == AF_INET) {
106                 struct in_addr broadcast;
107
108                 broadcast.s_addr = address->in_addr.in.s_addr | address->netmask.s_addr;
109
110                 r = sd_rtnl_message_append(req, IFA_BROADCAST, &broadcast);
111                 if (r < 0) {
112                         log_error("Could not append IFA_BROADCAST attribute: %s",
113                                   strerror(-r));
114                         return r;
115                 }
116         }
117
118         if (address->label) {
119                 r = sd_rtnl_message_append(req, IFA_LABEL, address->label);
120                 if (r < 0) {
121                         log_error("Could not append IFA_LABEL attribute: %s",
122                                   strerror(-r));
123                         return r;
124                 }
125         }
126
127         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
128         if (r < 0) {
129                 log_error("Could not send rtnetlink message: %s", strerror(-r));
130                 return r;
131         }
132
133         return 0;
134 }
135
136 int config_parse_address(const char *unit,
137                 const char *filename,
138                 unsigned line,
139                 const char *section,
140                 unsigned section_line,
141                 const char *lvalue,
142                 int ltype,
143                 const char *rvalue,
144                 void *data,
145                 void *userdata) {
146         Network *network = userdata;
147         _cleanup_address_free_ Address *n = NULL;
148         _cleanup_free_ char *address = NULL;
149         const char *e;
150         int r;
151
152         assert(filename);
153         assert(section);
154         assert(lvalue);
155         assert(rvalue);
156         assert(data);
157
158         if (streq(section, "Network")) {
159                 /* we are not in an Address section, so treat
160                  * this as the special '0' section */
161                 section_line = 0;
162         }
163
164         r = address_new(network, section_line, &n);
165         if (r < 0)
166                 return r;
167
168         /* Address=address/prefixlen */
169
170         /* prefixlen */
171         e = strchr(rvalue, '/');
172         if (e) {
173                 unsigned i;
174                 r = safe_atou(e + 1, &i);
175                 if (r < 0) {
176                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
177                                    "Interface prefix length is invalid, "
178                                    "ignoring assignment: %s", e + 1);
179                         return 0;
180                 }
181
182                 n->prefixlen = (unsigned char) i;
183                 n->netmask.s_addr = htonl(0xfffffffflu >> n->prefixlen);
184
185                 address = strndup(rvalue, e - rvalue);
186                 if (!address)
187                         return log_oom();
188         } else {
189                 address = strdup(rvalue);
190                 if (!address)
191                         return log_oom();
192         }
193
194         r = net_parse_inaddr(address, &n->family, &n->in_addr);
195         if (r < 0) {
196                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
197                            "Address is invalid, ignoring assignment: %s", address);
198                 return 0;
199         }
200
201         n = NULL;
202
203         return 0;
204 }
205
206 int config_parse_label(const char *unit,
207                 const char *filename,
208                 unsigned line,
209                 const char *section,
210                 unsigned section_line,
211                 const char *lvalue,
212                 int ltype,
213                 const char *rvalue,
214                 void *data,
215                 void *userdata) {
216         Network *network = userdata;
217         _cleanup_address_free_ Address *n = NULL;
218         char *label;
219         int r;
220
221         assert(filename);
222         assert(section);
223         assert(lvalue);
224         assert(rvalue);
225         assert(data);
226
227         r = address_new(network, section_line, &n);
228         if (r < 0)
229                 return r;
230
231         label = strdup(rvalue);
232         if (!label)
233                 return log_oom();
234
235         if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
236                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
237                            "Interface label is not ASCII clean or is too"
238                            " long, ignoring assignment: %s", rvalue);
239                 free(label);
240                 return 0;
241         }
242
243         free(n->label);
244         if (*label)
245                 n->label = label;
246         else {
247                 free(label);
248                 n->label = NULL;
249         }
250
251         n = NULL;
252
253         return 0;
254 }