chiark / gitweb /
bus: introduce concept of a "default" event loop per-thread and make use of it everywhere
[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(Manager *manager, Address *address, Link *link) {
59         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
60         int r;
61
62         r = sd_rtnl_message_addr_new(RTM_NEWADDR, link->ifindex,
63                         address->family, address->prefixlen,
64                         IFA_F_PERMANENT, RT_SCOPE_UNIVERSE, &req);
65         if (r < 0) {
66                 log_error("Could not allocate RTM_NEWADDR message: %s",
67                           strerror(-r));
68                 return r;
69         }
70
71         r = sd_rtnl_message_append(req, IFA_LOCAL, &address->in_addr);
72         if (r < 0) {
73                 log_error("Could not append IFA_LOCAL attribute: %s",
74                           strerror(-r));
75                 return r;
76         }
77
78         if (address->family == AF_INET) {
79                 struct in_addr broadcast;
80
81                 broadcast.s_addr = address->in_addr.in.s_addr |
82                                    htonl(0xfffffffflu >> address->prefixlen);
83
84                 r = sd_rtnl_message_append(req, IFA_BROADCAST, &broadcast);
85                 if (r < 0) {
86                         log_error("Could not append IFA_BROADCAST attribute: %s",
87                                   strerror(-r));
88                         return r;
89                 }
90         }
91
92         if (address->label) {
93                 r = sd_rtnl_message_append(req, IFA_LABEL, address->label);
94                 if (r < 0) {
95                         log_error("Could not append IFA_LABEL attribute: %s",
96                                   strerror(-r));
97                         return r;
98                 }
99         }
100
101         r = sd_rtnl_send_with_reply_and_block(manager->rtnl, req, 0, NULL);
102         if (r < 0) {
103                 log_error("Could not configure address: %s", strerror(-r));
104                 return r != -EEXIST ? r : 0;
105         }
106
107         log_info("Configured interface address");
108
109         return 0;
110 }
111
112 int config_parse_address(const char *unit,
113                 const char *filename,
114                 unsigned line,
115                 const char *section,
116                 const char *lvalue,
117                 int ltype,
118                 const char *rvalue,
119                 void *data,
120                 void *userdata) {
121         _cleanup_address_free_ Address *n = NULL;
122         _cleanup_free_ char *address = NULL;
123         const char *e;
124         int r;
125
126         assert(filename);
127         assert(lvalue);
128         assert(rvalue);
129         assert(data);
130
131         r = address_new(userdata, &n);
132         if (r < 0)
133                 return r;
134
135         /* Address=address/prefixlen */
136
137         /* prefixlen */
138         e = strchr(rvalue, '/');
139         if (e) {
140                 unsigned i;
141                 r = safe_atou(e + 1, &i);
142                 if (r < 0) {
143                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
144                                    "Interface prefix length is invalid, "
145                                    "ignoring assignment: %s", e + 1);
146                         return 0;
147                 }
148
149                 n->prefixlen = (unsigned char) i;
150                 address = strndup(rvalue, e - rvalue);
151                 if (!address)
152                         return log_oom();
153         } else {
154                 address = strdup(rvalue);
155                 if (!address)
156                         return log_oom();
157         }
158
159         r = net_parse_inaddr(address, &n->family, &n->in_addr);
160         if (r < 0) {
161                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
162                            "Address is invalid, ignoring assignment: %s", address);
163                 return 0;
164         }
165
166         n = NULL;
167
168         return 0;
169 }