Upgrade ofono to 1.2
[profile/ivi/ofono.git] / gatchat / ppp_ipv6cp.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2009-2011  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 <arpa/inet.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29
30 #include <errno.h>
31 #include <string.h>
32
33 #include <glib.h>
34
35 #include "gatppp.h"
36 #include "ppp.h"
37
38 #define IPV6CP_SUPPORTED_CODES  ((1 << PPPCP_CODE_TYPE_CONFIGURE_REQUEST) | \
39                                 (1 << PPPCP_CODE_TYPE_CONFIGURE_ACK) | \
40                                 (1 << PPPCP_CODE_TYPE_CONFIGURE_NAK) | \
41                                 (1 << PPPCP_CODE_TYPE_CONFIGURE_REJECT) | \
42                                 (1 << PPPCP_CODE_TYPE_TERMINATE_REQUEST) | \
43                                 (1 << PPPCP_CODE_TYPE_TERMINATE_ACK) | \
44                                 (1 << PPPCP_CODE_TYPE_CODE_REJECT))
45
46 #define OPTION_COPY(_options, _len, _req, _type, _var, _opt_len)        \
47         if (_req) {                                                     \
48                 _options[_len] = _type;                                 \
49                 _options[_len + 1] = _opt_len + 2;                      \
50                 memcpy(_options + _len + 2, _var, _opt_len);            \
51                 _len += _opt_len + 2;                                   \
52         }
53
54 /* We request only IPv6 Interface Id */
55 #define IPV6CP_MAX_CONFIG_OPTION_SIZE   10
56 #define IPV6CP_MAX_FAILURE              3
57 #define IPV6CP_ERROR ipv6cp_error_quark()
58
59 enum ipv6cp_option_types {
60         IPV6CP_INTERFACE_ID = 1,
61 };
62
63 struct ipv6cp_data {
64         guint8 options[IPV6CP_MAX_CONFIG_OPTION_SIZE];
65         guint16 options_len;
66         guint8 req_options;
67         guint64 local_addr;
68         guint64 peer_addr;
69         gboolean is_server;
70 };
71
72 static GQuark ipv6cp_error_quark(void)
73 {
74         return g_quark_from_static_string("ipv6cp");
75 }
76
77 static void ipv6cp_generate_config_options(struct ipv6cp_data *ipv6cp)
78 {
79         guint16 len = 0;
80
81         OPTION_COPY(ipv6cp->options, len,
82                         ipv6cp->req_options & IPV6CP_INTERFACE_ID,
83                         IPV6CP_INTERFACE_ID, &ipv6cp->local_addr,
84                         sizeof(ipv6cp->local_addr));
85
86         ipv6cp->options_len = len;
87 }
88
89 static void ipv6cp_reset_config_options(struct ipv6cp_data *ipv6cp)
90 {
91         ipv6cp->req_options = IPV6CP_INTERFACE_ID;
92
93         ipv6cp_generate_config_options(ipv6cp);
94 }
95
96 static void ipv6cp_up(struct pppcp_data *pppcp)
97 {
98
99 }
100
101 static void ipv6cp_down(struct pppcp_data *pppcp)
102 {
103         struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
104
105         ipv6cp_reset_config_options(ipv6cp);
106
107         pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
108 }
109
110 static void ipv6cp_finished(struct pppcp_data *pppcp)
111 {
112
113 }
114
115 static enum rcr_result ipv6cp_server_rcr(struct ipv6cp_data *ipv6cp,
116                                         const struct pppcp_packet *packet,
117                                         guint8 **new_options, guint16 *new_len)
118 {
119         struct ppp_option_iter iter;
120         guint8 nak_options[IPV6CP_MAX_CONFIG_OPTION_SIZE];
121         guint16 len = 0;
122         guint8 *rej_options = NULL;
123         guint16 rej_len = 0;
124         guint64 addr;
125
126         ppp_option_iter_init(&iter, packet);
127
128         while (ppp_option_iter_next(&iter) == TRUE) {
129                 guint8 type = ppp_option_iter_get_type(&iter);
130                 const void *data = ppp_option_iter_get_data(&iter);
131
132                 switch (type) {
133                 case IPV6CP_INTERFACE_ID:
134                         memcpy(&addr, data, sizeof(addr));
135
136                         OPTION_COPY(nak_options, len,
137                                         addr != ipv6cp->peer_addr || addr == 0,
138                                         type, &ipv6cp->peer_addr,
139                                         ppp_option_iter_get_length(&iter));
140                         break;
141                 default:
142                         if (rej_options == NULL) {
143                                 guint16 max_len = ntohs(packet->length) - 4;
144                                 rej_options = g_new0(guint8, max_len);
145                         }
146
147                         OPTION_COPY(rej_options, rej_len, rej_options != NULL,
148                                         type, data,
149                                         ppp_option_iter_get_length(&iter));
150                         break;
151                 }
152         }
153
154         if (rej_len > 0) {
155                 *new_len = rej_len;
156                 *new_options = rej_options;
157
158                 return RCR_REJECT;
159         }
160
161         if (len > 0) {
162                 *new_len = len;
163                 *new_options = g_memdup(nak_options, len);
164
165                 return RCR_NAK;
166         }
167
168         return RCR_ACCEPT;
169 }
170
171 static enum rcr_result ipv6cp_client_rcr(struct ipv6cp_data *ipv6cp,
172                                         const struct pppcp_packet *packet,
173                                         guint8 **new_options, guint16 *new_len)
174 {
175         struct ppp_option_iter iter;
176         guint8 *options = NULL;
177         guint8 len = 0;
178
179         ppp_option_iter_init(&iter, packet);
180
181         while (ppp_option_iter_next(&iter) == TRUE) {
182                 guint8 type = ppp_option_iter_get_type(&iter);
183                 const void *data = ppp_option_iter_get_data(&iter);
184
185                 switch (type) {
186                 case IPV6CP_INTERFACE_ID:
187                         memcpy(&ipv6cp->peer_addr, data,
188                                         sizeof(ipv6cp->peer_addr));
189
190                         if (ipv6cp->peer_addr != 0)
191                                 break;
192                         /*
193                          * Fall through, reject zero Interface ID
194                          */
195                 default:
196                         if (options == NULL) {
197                                 guint16 max_len = ntohs(packet->length) - 4;
198                                 options = g_new0(guint8, max_len);
199                         }
200
201                         OPTION_COPY(options, len, options != NULL,
202                                         type, data,
203                                         ppp_option_iter_get_length(&iter));
204                         break;
205                 }
206         }
207
208         if (len > 0) {
209                 *new_len = len;
210                 *new_options = options;
211
212                 return RCR_REJECT;
213         }
214
215         return RCR_ACCEPT;
216 }
217
218 static enum rcr_result ipv6cp_rcr(struct pppcp_data *pppcp,
219                                         const struct pppcp_packet *packet,
220                                         guint8 **new_options, guint16 *new_len)
221 {
222         struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
223
224         if (ipv6cp->is_server)
225                 return ipv6cp_server_rcr(ipv6cp, packet, new_options, new_len);
226         else
227                 return ipv6cp_client_rcr(ipv6cp, packet, new_options, new_len);
228 }
229
230 static void ipv6cp_rca(struct pppcp_data *pppcp,
231                                         const struct pppcp_packet *packet)
232 {
233         struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
234         struct ppp_option_iter iter;
235
236         if (ipv6cp->is_server)
237                 return;
238
239         ppp_option_iter_init(&iter, packet);
240
241         while (ppp_option_iter_next(&iter) == TRUE) {
242                 const guint8 *data = ppp_option_iter_get_data(&iter);
243
244                 switch (ppp_option_iter_get_type(&iter)) {
245                 case IPV6CP_INTERFACE_ID:
246                         memcpy(&ipv6cp->local_addr, data,
247                                         sizeof(ipv6cp->local_addr));
248                         break;
249                 default:
250                         break;
251                 }
252         }
253 }
254
255 static void ipv6cp_rcn_nak(struct pppcp_data *pppcp,
256                                 const struct pppcp_packet *packet)
257 {
258         struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
259         struct ppp_option_iter iter;
260
261         if (ipv6cp->is_server)
262                 return;
263
264         ppp_option_iter_init(&iter, packet);
265
266         while (ppp_option_iter_next(&iter) == TRUE) {
267                 const guint8 *data = ppp_option_iter_get_data(&iter);
268
269                 switch (ppp_option_iter_get_type(&iter)) {
270                 case IPV6CP_INTERFACE_ID:
271                         ipv6cp->req_options |= IPV6CP_INTERFACE_ID;
272                         memcpy(&ipv6cp->local_addr, data,
273                                 sizeof(ipv6cp->local_addr));
274                         break;
275                 default:
276                         break;
277                 }
278         }
279
280         ipv6cp_generate_config_options(ipv6cp);
281         pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
282 }
283
284 static void ipv6cp_rcn_rej(struct pppcp_data *pppcp,
285                                 const struct pppcp_packet *packet)
286 {
287         struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
288         struct ppp_option_iter iter;
289
290         ppp_option_iter_init(&iter, packet);
291
292         while (ppp_option_iter_next(&iter) == TRUE) {
293                 switch (ppp_option_iter_get_type(&iter)) {
294                 case IPV6CP_INTERFACE_ID:
295                         ipv6cp->req_options &= ~IPV6CP_INTERFACE_ID;
296                         break;
297                 default:
298                         break;
299                 }
300         }
301
302         ipv6cp_generate_config_options(ipv6cp);
303         pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
304 }
305
306 struct pppcp_proto ipv6cp_proto = {
307         .proto                  = IPV6CP_PROTO,
308         .name                   = "ipv6cp",
309         .supported_codes        = IPV6CP_SUPPORTED_CODES,
310         .this_layer_up          = ipv6cp_up,
311         .this_layer_down        = ipv6cp_down,
312         .this_layer_finished    = ipv6cp_finished,
313         .rca                    = ipv6cp_rca,
314         .rcn_nak                = ipv6cp_rcn_nak,
315         .rcn_rej                = ipv6cp_rcn_rej,
316         .rcr                    = ipv6cp_rcr,
317 };
318
319 struct pppcp_data *ipv6cp_new(GAtPPP *ppp, gboolean is_server,
320                                         const char *local, const char *peer,
321                                         GError **error)
322 {
323         struct ipv6cp_data *ipv6cp;
324         struct pppcp_data *pppcp;
325         struct in6_addr local_addr;
326         struct in6_addr peer_addr;
327
328         if (local == NULL)
329                 memset(&local_addr, 0, sizeof(local_addr));
330         else if (inet_pton(AF_INET6, local, &local_addr) != 1) {
331                 g_set_error(error, IPV6CP_ERROR, errno,
332                                 "Unable to set local Interface ID: %s",
333                                 strerror(errno));
334                 return NULL;
335         }
336
337         if (peer == NULL)
338                 memset(&peer_addr, 0, sizeof(peer_addr));
339         else if (inet_pton(AF_INET6, peer, &peer_addr) != 1) {
340                 g_set_error(error, IPV6CP_ERROR, errno,
341                                 "Unable to set peer Interface ID: %s",
342                                 g_strerror(errno));
343                 return NULL;
344         }
345
346         ipv6cp = g_try_new0(struct ipv6cp_data, 1);
347         if (ipv6cp == NULL)
348                 return NULL;
349
350         pppcp = pppcp_new(ppp, &ipv6cp_proto, FALSE, IPV6CP_MAX_FAILURE);
351         if (pppcp == NULL) {
352                 g_free(ipv6cp);
353                 return NULL;
354         }
355
356         memcpy(&ipv6cp->local_addr, &local_addr.s6_addr[8],
357                                                 sizeof(ipv6cp->local_addr));
358         memcpy(&ipv6cp->peer_addr, &peer_addr.s6_addr[8],
359                                                 sizeof(ipv6cp->peer_addr));
360         ipv6cp->is_server = is_server;
361
362         pppcp_set_data(pppcp, ipv6cp);
363
364         ipv6cp_reset_config_options(ipv6cp);
365
366         pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
367
368         return pppcp;
369 }
370
371 void ipv6cp_free(struct pppcp_data *data)
372 {
373         struct ipv6cp_data *ipv6cp = pppcp_get_data(data);
374
375         g_free(ipv6cp);
376         pppcp_free(data);
377 }