chiark / gitweb /
conf-parser: distinguish between multiple sections with the same name
[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, Address **ret) {
32         _cleanup_address_free_ Address *address = NULL;
33
34         address = new0(Address, 1);
35         if (!address)
36                 return -ENOMEM;
37
38         address->network = network;
39
40         LIST_PREPEND(addresses, network->addresses, address);
41
42         *ret = address;
43         address = NULL;
44
45         return 0;
46 }
47
48 void address_free(Address *address) {
49         if (!address)
50                 return;
51
52         LIST_REMOVE(addresses, address->network->addresses, address);
53
54         free(address->label);
55         free(address);
56 }
57
58 int address_configure(Address *address, Link *link,
59                       sd_rtnl_message_handler_t callback) {
60         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
61         int r;
62
63         assert(link->manager);
64
65         r = sd_rtnl_message_addr_new(RTM_NEWADDR, link->ifindex,
66                         address->family, address->prefixlen,
67                         IFA_F_PERMANENT, RT_SCOPE_UNIVERSE, &req);
68         if (r < 0) {
69                 log_error("Could not allocate RTM_NEWADDR message: %s",
70                           strerror(-r));
71                 return r;
72         }
73
74         r = sd_rtnl_message_append(req, IFA_LOCAL, &address->in_addr);
75         if (r < 0) {
76                 log_error("Could not append IFA_LOCAL attribute: %s",
77                           strerror(-r));
78                 return r;
79         }
80
81         if (address->family == AF_INET) {
82                 struct in_addr broadcast;
83
84                 broadcast.s_addr = address->in_addr.in.s_addr | address->netmask.s_addr;
85
86                 r = sd_rtnl_message_append(req, IFA_BROADCAST, &broadcast);
87                 if (r < 0) {
88                         log_error("Could not append IFA_BROADCAST attribute: %s",
89                                   strerror(-r));
90                         return r;
91                 }
92         }
93
94         if (address->label) {
95                 r = sd_rtnl_message_append(req, IFA_LABEL, address->label);
96                 if (r < 0) {
97                         log_error("Could not append IFA_LABEL attribute: %s",
98                                   strerror(-r));
99                         return r;
100                 }
101         }
102
103         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
104         if (r < 0) {
105                 log_error("Could not send rtnetlink message: %s", strerror(-r));
106                 return r;
107         }
108
109         link->rtnl_messages ++;
110
111         return 0;
112 }
113
114 int config_parse_address(const char *unit,
115                 const char *filename,
116                 unsigned line,
117                 const char *section,
118                 unsigned section_line,
119                 const char *lvalue,
120                 int ltype,
121                 const char *rvalue,
122                 void *data,
123                 void *userdata) {
124         _cleanup_address_free_ Address *n = NULL;
125         _cleanup_free_ char *address = NULL;
126         const char *e;
127         int r;
128
129         assert(filename);
130         assert(lvalue);
131         assert(rvalue);
132         assert(data);
133
134         r = address_new(userdata, &n);
135         if (r < 0)
136                 return r;
137
138         /* Address=address/prefixlen */
139
140         /* prefixlen */
141         e = strchr(rvalue, '/');
142         if (e) {
143                 unsigned i;
144                 r = safe_atou(e + 1, &i);
145                 if (r < 0) {
146                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
147                                    "Interface prefix length is invalid, "
148                                    "ignoring assignment: %s", e + 1);
149                         return 0;
150                 }
151
152                 n->prefixlen = (unsigned char) i;
153                 n->netmask.s_addr = htonl(0xfffffffflu >> n->prefixlen);
154
155                 address = strndup(rvalue, e - rvalue);
156                 if (!address)
157                         return log_oom();
158         } else {
159                 address = strdup(rvalue);
160                 if (!address)
161                         return log_oom();
162         }
163
164         r = net_parse_inaddr(address, &n->family, &n->in_addr);
165         if (r < 0) {
166                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
167                            "Address is invalid, ignoring assignment: %s", address);
168                 return 0;
169         }
170
171         n = NULL;
172
173         return 0;
174 }