chiark / gitweb /
networkd: make all calls async
[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                 const char *lvalue,
119                 int ltype,
120                 const char *rvalue,
121                 void *data,
122                 void *userdata) {
123         _cleanup_address_free_ Address *n = NULL;
124         _cleanup_free_ char *address = NULL;
125         const char *e;
126         int r;
127
128         assert(filename);
129         assert(lvalue);
130         assert(rvalue);
131         assert(data);
132
133         r = address_new(userdata, &n);
134         if (r < 0)
135                 return r;
136
137         /* Address=address/prefixlen */
138
139         /* prefixlen */
140         e = strchr(rvalue, '/');
141         if (e) {
142                 unsigned i;
143                 r = safe_atou(e + 1, &i);
144                 if (r < 0) {
145                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
146                                    "Interface prefix length is invalid, "
147                                    "ignoring assignment: %s", e + 1);
148                         return 0;
149                 }
150
151                 n->prefixlen = (unsigned char) i;
152                 n->netmask.s_addr = htonl(0xfffffffflu >> n->prefixlen);
153
154                 address = strndup(rvalue, e - rvalue);
155                 if (!address)
156                         return log_oom();
157         } else {
158                 address = strdup(rvalue);
159                 if (!address)
160                         return log_oom();
161         }
162
163         r = net_parse_inaddr(address, &n->family, &n->in_addr);
164         if (r < 0) {
165                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
166                            "Address is invalid, ignoring assignment: %s", address);
167                 return 0;
168         }
169
170         n = NULL;
171
172         return 0;
173 }