chiark / gitweb /
sd-dhcp6-client: Add initial DHCPv6 client files
[elogind.git] / src / libsystemd-network / sd-dhcp6-client.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright (C) 2014 Intel Corporation. All rights reserved.
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 <errno.h>
23 #include <string.h>
24
25 #include "util.h"
26 #include "refcnt.h"
27
28 #include "sd-dhcp6-client.h"
29 #include "dhcp6-protocol.h"
30
31 struct sd_dhcp6_client {
32         RefCount n_ref;
33
34         enum DHCP6State state;
35         sd_event *event;
36         int event_priority;
37         int index;
38         struct ether_addr mac_addr;
39         sd_dhcp6_client_cb_t cb;
40         void *userdata;
41 };
42
43 int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
44                                  sd_dhcp6_client_cb_t cb, void *userdata)
45 {
46         assert_return(client, -EINVAL);
47
48         client->cb = cb;
49         client->userdata = userdata;
50
51         return 0;
52 }
53
54 int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index)
55 {
56         assert_return(client, -EINVAL);
57         assert_return(interface_index >= -1, -EINVAL);
58
59         client->index = interface_index;
60
61         return 0;
62 }
63
64 int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
65                             const struct ether_addr *mac_addr)
66 {
67         assert_return(client, -EINVAL);
68
69         if (mac_addr)
70                 memcpy(&client->mac_addr, mac_addr, sizeof(client->mac_addr));
71         else
72                 memset(&client->mac_addr, 0x00, sizeof(client->mac_addr));
73
74         return 0;
75 }
76
77 static sd_dhcp6_client *client_notify(sd_dhcp6_client *client, int event) {
78         if (client->cb) {
79                 client = sd_dhcp6_client_ref(client);
80                 client->cb(client, event, client->userdata);
81                 client = sd_dhcp6_client_unref(client);
82         }
83
84         return client;
85 }
86
87 static int client_initialize(sd_dhcp6_client *client)
88 {
89         assert_return(client, -EINVAL);
90
91         client->state = DHCP6_STATE_STOPPED;
92
93         return 0;
94 }
95
96 static sd_dhcp6_client *client_stop(sd_dhcp6_client *client, int error) {
97         assert_return(client, NULL);
98
99         client = client_notify(client, error);
100         if (client)
101                 client_initialize(client);
102
103         return client;
104 }
105
106 int sd_dhcp6_client_stop(sd_dhcp6_client *client)
107 {
108         client_stop(client, DHCP6_EVENT_STOP);
109
110         return 0;
111 }
112
113 int sd_dhcp6_client_start(sd_dhcp6_client *client)
114 {
115         int r = 0;
116
117         assert_return(client, -EINVAL);
118         assert_return(client->event, -EINVAL);
119         assert_return(client->index > 0, -EINVAL);
120
121         return r;
122 }
123
124 int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
125                                  int priority)
126 {
127         int r;
128
129         assert_return(client, -EINVAL);
130         assert_return(!client->event, -EBUSY);
131
132         if (event)
133                 client->event = sd_event_ref(event);
134         else {
135                 r = sd_event_default(&client->event);
136                 if (r < 0)
137                         return 0;
138         }
139
140         client->event_priority = priority;
141
142         return 0;
143 }
144
145 int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) {
146         assert_return(client, -EINVAL);
147
148         client->event = sd_event_unref(client->event);
149
150         return 0;
151 }
152
153 sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
154         if (!client)
155                 return NULL;
156
157         return client->event;
158 }
159
160 sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
161         if (client)
162                 assert_se(REFCNT_INC(client->n_ref) >= 2);
163
164         return client;
165 }
166
167 sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
168         if (client && REFCNT_DEC(client->n_ref) <= 0) {
169
170                 client_initialize(client);
171
172                 sd_dhcp6_client_detach_event(client);
173
174                 free(client);
175
176                 return NULL;
177         }
178
179         return client;
180 }
181
182 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref);
183 #define _cleanup_dhcp6_client_free_ _cleanup_(sd_dhcp6_client_unrefp)
184
185 int sd_dhcp6_client_new(sd_dhcp6_client **ret)
186 {
187         _cleanup_dhcp6_client_free_ sd_dhcp6_client *client = NULL;
188
189         assert_return(ret, -EINVAL);
190
191         client = new0(sd_dhcp6_client, 1);
192         if (!client)
193                 return -ENOMEM;
194
195         client->n_ref = REFCNT_INIT;
196
197         client->index = -1;
198
199         *ret = client;
200         client = NULL;
201
202         return 0;
203 }