Merge "Fix SIGSEV on freeing server domains list" into tizen
[platform/upstream/connman.git] / src / ipaddress.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <glib.h>
31
32 #include <connman/ipaddress.h>
33
34 #include "connman.h"
35
36 unsigned char connman_ipaddress_calc_netmask_len(const char *netmask)
37 {
38         unsigned char bits;
39         in_addr_t mask;
40         in_addr_t host;
41
42         if (!netmask)
43                 return 32;
44
45         mask = inet_network(netmask);
46         host = ~mask;
47
48         /* a valid netmask must be 2^n - 1 */
49         if ((host & (host + 1)) != 0)
50                 return -1;
51
52         bits = 0;
53         for (; mask; mask <<= 1)
54                 ++bits;
55
56         return bits;
57 }
58
59 struct connman_ipaddress *connman_ipaddress_alloc(int family)
60 {
61         struct connman_ipaddress *ipaddress;
62
63         ipaddress = g_try_new0(struct connman_ipaddress, 1);
64         if (!ipaddress)
65                 return NULL;
66
67         ipaddress->family = family;
68         ipaddress->prefixlen = 0;
69         ipaddress->local = NULL;
70         ipaddress->peer = NULL;
71         ipaddress->broadcast = NULL;
72         ipaddress->gateway = NULL;
73         ipaddress->is_p2p = false;
74
75         return ipaddress;
76 }
77
78 void connman_ipaddress_set_p2p(struct connman_ipaddress *ipaddress, bool value)
79 {
80         if (!ipaddress)
81                 return;
82
83         ipaddress->is_p2p = value;
84 }
85
86 void connman_ipaddress_free(struct connman_ipaddress *ipaddress)
87 {
88         if (!ipaddress)
89                 return;
90
91         g_free(ipaddress->broadcast);
92         g_free(ipaddress->peer);
93         g_free(ipaddress->local);
94         g_free(ipaddress->gateway);
95         g_free(ipaddress);
96 }
97
98 static bool check_ipv6_address(const char *address)
99 {
100         unsigned char buf[sizeof(struct in6_addr)];
101         int err;
102
103         if (!address)
104                 return false;
105
106         err = inet_pton(AF_INET6, address, buf);
107         if (err == 1)
108                 return true;
109
110         return false;
111 }
112
113 int connman_ipaddress_set_ipv6(struct connman_ipaddress *ipaddress,
114                                 const char *address,
115                                 unsigned char prefix_length,
116                                 const char *gateway)
117 {
118         if (!ipaddress)
119                 return -EINVAL;
120
121         if (!check_ipv6_address(address))
122                 return -EINVAL;
123
124         DBG("prefix_len %d address %s gateway %s",
125                         prefix_length, address, gateway);
126
127         ipaddress->family = AF_INET6;
128
129         ipaddress->prefixlen = prefix_length;
130
131         g_free(ipaddress->local);
132         ipaddress->local = g_strdup(address);
133
134         g_free(ipaddress->gateway);
135         ipaddress->gateway = g_strdup(gateway);
136
137         return 0;
138 }
139
140 int connman_ipaddress_get_ip(struct connman_ipaddress *ipaddress,
141                         const char **address,
142                         unsigned char *netmask_prefix_length)
143 {
144         if (!ipaddress)
145                 return -EINVAL;
146
147         *netmask_prefix_length = ipaddress->prefixlen;
148         *address = ipaddress->local;
149
150         return 0;
151 }
152
153 int connman_ipaddress_set_ipv4(struct connman_ipaddress *ipaddress,
154                 const char *address, const char *netmask, const char *gateway)
155 {
156         if (!ipaddress)
157                 return -EINVAL;
158
159         ipaddress->family = AF_INET;
160
161         ipaddress->prefixlen = connman_ipaddress_calc_netmask_len(netmask);
162
163         g_free(ipaddress->local);
164         ipaddress->local = g_strdup(address);
165
166         g_free(ipaddress->gateway);
167         ipaddress->gateway = g_strdup(gateway);
168
169         return 0;
170 }
171
172 void connman_ipaddress_set_peer(struct connman_ipaddress *ipaddress,
173                                 const char *peer)
174 {
175         if (!ipaddress)
176                 return;
177
178         g_free(ipaddress->peer);
179         ipaddress->peer = g_strdup(peer);
180 }
181
182 void connman_ipaddress_clear(struct connman_ipaddress *ipaddress)
183 {
184         if (!ipaddress)
185                 return;
186
187         ipaddress->prefixlen = 0;
188
189         g_free(ipaddress->local);
190         ipaddress->local = NULL;
191
192         g_free(ipaddress->peer);
193         ipaddress->peer = NULL;
194
195         g_free(ipaddress->broadcast);
196         ipaddress->broadcast = NULL;
197
198         g_free(ipaddress->gateway);
199         ipaddress->gateway = NULL;
200 }
201
202 /*
203  * Note that this copy function only copies the actual address and
204  * prefixlen. Use the other copy function to copy the whole struct.
205  */
206 void connman_ipaddress_copy_address(struct connman_ipaddress *ipaddress,
207                                         struct connman_ipaddress *source)
208 {
209         if (!ipaddress || !source)
210                 return;
211
212         ipaddress->family = source->family;
213         ipaddress->prefixlen = source->prefixlen;
214
215         g_free(ipaddress->local);
216         ipaddress->local = g_strdup(source->local);
217 }
218
219 struct connman_ipaddress *
220 connman_ipaddress_copy(struct connman_ipaddress *ipaddress)
221 {
222         struct connman_ipaddress *copy;
223
224         if (!ipaddress)
225                 return NULL;
226
227         copy = g_new0(struct connman_ipaddress, 1);
228
229         copy->family = ipaddress->family;
230         copy->prefixlen = ipaddress->prefixlen;
231         copy->local = g_strdup(ipaddress->local);
232         copy->peer = g_strdup(ipaddress->peer);
233         copy->broadcast = g_strdup(ipaddress->broadcast);
234         copy->gateway = g_strdup(ipaddress->gateway);
235         copy->is_p2p = ipaddress->is_p2p;
236
237         return copy;
238 }