3 * oFono - Open Source Telephony
5 * Copyright (C) 2009-2011 Intel Corporation. All rights reserved.
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.
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.
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
26 #include <arpa/inet.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
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))
46 #define OPTION_COPY(_options, _len, _req, _type, _var, _opt_len) \
48 _options[_len] = _type; \
49 _options[_len + 1] = _opt_len + 2; \
50 memcpy(_options + _len + 2, _var, _opt_len); \
51 _len += _opt_len + 2; \
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()
59 enum ipv6cp_option_types {
60 IPV6CP_INTERFACE_ID = 1,
64 guint8 options[IPV6CP_MAX_CONFIG_OPTION_SIZE];
72 static GQuark ipv6cp_error_quark(void)
74 return g_quark_from_static_string("ipv6cp");
77 static void ipv6cp_generate_config_options(struct ipv6cp_data *ipv6cp)
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));
86 ipv6cp->options_len = len;
89 static void ipv6cp_reset_config_options(struct ipv6cp_data *ipv6cp)
91 ipv6cp->req_options = IPV6CP_INTERFACE_ID;
93 ipv6cp_generate_config_options(ipv6cp);
96 static void ipv6cp_up(struct pppcp_data *pppcp)
101 static void ipv6cp_down(struct pppcp_data *pppcp)
103 struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
105 ipv6cp_reset_config_options(ipv6cp);
107 pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
110 static void ipv6cp_finished(struct pppcp_data *pppcp)
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)
119 struct ppp_option_iter iter;
120 guint8 nak_options[IPV6CP_MAX_CONFIG_OPTION_SIZE];
122 guint8 *rej_options = NULL;
126 ppp_option_iter_init(&iter, packet);
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);
133 case IPV6CP_INTERFACE_ID:
134 memcpy(&addr, data, sizeof(addr));
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));
142 if (rej_options == NULL) {
143 guint16 max_len = ntohs(packet->length) - 4;
144 rej_options = g_new0(guint8, max_len);
147 OPTION_COPY(rej_options, rej_len, rej_options != NULL,
149 ppp_option_iter_get_length(&iter));
156 *new_options = rej_options;
163 *new_options = g_memdup(nak_options, len);
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)
175 struct ppp_option_iter iter;
176 guint8 *options = NULL;
179 ppp_option_iter_init(&iter, packet);
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);
186 case IPV6CP_INTERFACE_ID:
187 memcpy(&ipv6cp->peer_addr, data,
188 sizeof(ipv6cp->peer_addr));
190 if (ipv6cp->peer_addr != 0)
193 * Fall through, reject zero Interface ID
196 if (options == NULL) {
197 guint16 max_len = ntohs(packet->length) - 4;
198 options = g_new0(guint8, max_len);
201 OPTION_COPY(options, len, options != NULL,
203 ppp_option_iter_get_length(&iter));
210 *new_options = options;
218 static enum rcr_result ipv6cp_rcr(struct pppcp_data *pppcp,
219 const struct pppcp_packet *packet,
220 guint8 **new_options, guint16 *new_len)
222 struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
224 if (ipv6cp->is_server)
225 return ipv6cp_server_rcr(ipv6cp, packet, new_options, new_len);
227 return ipv6cp_client_rcr(ipv6cp, packet, new_options, new_len);
230 static void ipv6cp_rca(struct pppcp_data *pppcp,
231 const struct pppcp_packet *packet)
233 struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
234 struct ppp_option_iter iter;
236 if (ipv6cp->is_server)
239 ppp_option_iter_init(&iter, packet);
241 while (ppp_option_iter_next(&iter) == TRUE) {
242 const guint8 *data = ppp_option_iter_get_data(&iter);
244 switch (ppp_option_iter_get_type(&iter)) {
245 case IPV6CP_INTERFACE_ID:
246 memcpy(&ipv6cp->local_addr, data,
247 sizeof(ipv6cp->local_addr));
255 static void ipv6cp_rcn_nak(struct pppcp_data *pppcp,
256 const struct pppcp_packet *packet)
258 struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
259 struct ppp_option_iter iter;
261 if (ipv6cp->is_server)
264 ppp_option_iter_init(&iter, packet);
266 while (ppp_option_iter_next(&iter) == TRUE) {
267 const guint8 *data = ppp_option_iter_get_data(&iter);
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));
280 ipv6cp_generate_config_options(ipv6cp);
281 pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
284 static void ipv6cp_rcn_rej(struct pppcp_data *pppcp,
285 const struct pppcp_packet *packet)
287 struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
288 struct ppp_option_iter iter;
290 ppp_option_iter_init(&iter, packet);
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;
302 ipv6cp_generate_config_options(ipv6cp);
303 pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
306 struct pppcp_proto ipv6cp_proto = {
307 .proto = IPV6CP_PROTO,
309 .supported_codes = IPV6CP_SUPPORTED_CODES,
310 .this_layer_up = ipv6cp_up,
311 .this_layer_down = ipv6cp_down,
312 .this_layer_finished = ipv6cp_finished,
314 .rcn_nak = ipv6cp_rcn_nak,
315 .rcn_rej = ipv6cp_rcn_rej,
319 struct pppcp_data *ipv6cp_new(GAtPPP *ppp, gboolean is_server,
320 const char *local, const char *peer,
323 struct ipv6cp_data *ipv6cp;
324 struct pppcp_data *pppcp;
325 struct in6_addr local_addr;
326 struct in6_addr peer_addr;
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",
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",
346 ipv6cp = g_try_new0(struct ipv6cp_data, 1);
350 pppcp = pppcp_new(ppp, &ipv6cp_proto, FALSE, IPV6CP_MAX_FAILURE);
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;
362 pppcp_set_data(pppcp, ipv6cp);
364 ipv6cp_reset_config_options(ipv6cp);
366 pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
371 void ipv6cp_free(struct pppcp_data *data)
373 struct ipv6cp_data *ipv6cp = pppcp_get_data(data);