* [PATCH 0/1] Initial patches for gatchat IPv6 CP support
@ 2011-10-26 14:20 Oleg Zhurakivskyy
2011-10-26 14:20 ` [PATCH 1/1] gatchat: Add " Oleg Zhurakivskyy
0 siblings, 1 reply; 4+ messages in thread
From: Oleg Zhurakivskyy @ 2011-10-26 14:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1000 bytes --]
Hello,
These patches implement IPv6 Control Protocol support for gatchat. The implementation is based and following gatchat's IPCP approach.
I tested with gsmdial and test-server, basic cases already work. In case anyone wants to initiate IPv6 CP address negotiation, patches to gsmdial and test-server are included.
These patches aren't complete, things yet to be done:
- Error case (Configure-Reject)
- Connect callback actions
- Proper integration with IPCP
I would appreciate your feedback.
Regards,
Oleg
Oleg Zhurakivskyy (1):
gatchat: Add IPv6 CP support
Makefile.am | 2 +-
gatchat/gatppp.c | 58 +++++++++-
gatchat/gatppp.h | 2 +
gatchat/gsmdial.c | 6 +
gatchat/ppp.h | 23 ++++
gatchat/ppp_ipv6cp.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++
gatchat/test-server.c | 17 +++-
7 files changed, 410 insertions(+), 4 deletions(-)
create mode 100644 gatchat/ppp_ipv6cp.c
--
1.7.4.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/1] gatchat: Add IPv6 CP support
2011-10-26 14:20 [PATCH 0/1] Initial patches for gatchat IPv6 CP support Oleg Zhurakivskyy
@ 2011-10-26 14:20 ` Oleg Zhurakivskyy
2011-10-31 7:43 ` Denis Kenzior
0 siblings, 1 reply; 4+ messages in thread
From: Oleg Zhurakivskyy @ 2011-10-26 14:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 18025 bytes --]
---
Makefile.am | 2 +-
gatchat/gatppp.c | 58 +++++++++-
gatchat/gatppp.h | 2 +
gatchat/gsmdial.c | 6 +
gatchat/ppp.h | 23 ++++
gatchat/ppp_ipv6cp.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++
gatchat/test-server.c | 17 +++-
7 files changed, 410 insertions(+), 4 deletions(-)
create mode 100644 gatchat/ppp_ipv6cp.c
diff --git a/Makefile.am b/Makefile.am
index 83b7737..44fdfff 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -76,7 +76,7 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
gatchat/ppp.h gatchat/ppp_cp.h \
gatchat/ppp_cp.c gatchat/ppp_lcp.c \
gatchat/ppp_auth.c gatchat/ppp_net.c \
- gatchat/ppp_ipcp.c
+ gatchat/ppp_ipcp.c gatchat/ppp_ipv6cp.c
gisi_sources = gisi/client.c gisi/client.h gisi/common.h \
gisi/iter.c gisi/iter.h \
diff --git a/gatchat/gatppp.c b/gatchat/gatppp.c
index f767f4a..41f9dff 100644
--- a/gatchat/gatppp.c
+++ b/gatchat/gatppp.c
@@ -62,6 +62,7 @@ struct _GAtPPP {
enum ppp_phase phase;
struct pppcp_data *lcp;
struct pppcp_data *ipcp;
+ struct pppcp_data *ipv6cp;
struct ppp_net *net;
struct ppp_chap *chap;
GAtHDLC *hdlc;
@@ -157,7 +158,8 @@ static inline gboolean ppp_drop_packet(GAtPPP *ppp, guint16 protocol)
return TRUE;
case PPP_PHASE_NETWORK:
if (protocol != LCP_PROTOCOL && protocol != CHAP_PROTOCOL &&
- protocol != IPCP_PROTO)
+ protocol != IPCP_PROTO &&
+ protocol != IPV6CP_PROTO)
return TRUE;
break;
case PPP_PHASE_LINK_UP:
@@ -222,6 +224,10 @@ static void ppp_receive(const unsigned char *buf, gsize len, void *data)
case IPCP_PROTO:
pppcp_process_packet(ppp->ipcp, packet, len - offset);
break;
+ case IPV6CP_PROTO:
+ if (ppp->ipv6cp)
+ pppcp_process_packet(ppp->ipv6cp, packet, len - offset);
+ break;
case CHAP_PROTOCOL:
if (ppp->chap) {
ppp_chap_process_packet(ppp->chap, packet,
@@ -381,6 +387,13 @@ void ppp_auth_notify(GAtPPP *ppp, gboolean success)
ppp_enter_phase(ppp, PPP_PHASE_NETWORK);
+ /* Send UP & OPEN events to the IPv6 CP */
+ if (ppp->ipv6cp) {
+ pppcp_signal_open(ppp->ipv6cp);
+ pppcp_signal_up(ppp->ipv6cp);
+ return;
+ }
+
/* Send UP & OPEN events to the IPCP layer */
pppcp_signal_open(ppp->ipcp);
pppcp_signal_up(ppp->ipcp);
@@ -435,6 +448,28 @@ void ppp_ipcp_finished_notify(GAtPPP *ppp)
pppcp_signal_close(ppp->lcp);
}
+void ppp_ipv6cp_up_notify(GAtPPP *ppp, const char *local, const char *peer)
+{
+ DBG(ppp, "local: %s, peer: %s", local, peer);
+}
+
+void ppp_ipv6cp_down_notify(GAtPPP *ppp)
+{
+ DBG(ppp, "");
+}
+
+void ppp_ipv6cp_finished_notify(GAtPPP *ppp)
+{
+ DBG(ppp, "");
+
+ if (ppp->phase != PPP_PHASE_NETWORK)
+ return;
+
+ ppp->disconnect_reason = G_AT_PPP_REASON_IPV6CP_FAIL;
+ pppcp_signal_close(ppp->ipv6cp);
+ pppcp_signal_close(ppp->lcp);
+}
+
void ppp_lcp_up_notify(GAtPPP *ppp)
{
/* Wait for the peer to send us a challenge if we expect auth */
@@ -732,6 +767,8 @@ void g_at_ppp_unref(GAtPPP *ppp)
lcp_free(ppp->lcp);
ipcp_free(ppp->ipcp);
+ if (ppp->ipv6cp)
+ ipv6cp_free(ppp->ipv6cp);
if (ppp->ppp_dead_source) {
g_source_remove(ppp->ppp_dead_source);
@@ -772,6 +809,25 @@ void g_at_ppp_set_pfc_enabled(GAtPPP *ppp, gboolean enabled)
lcp_set_pfc_enabled(ppp->lcp, enabled);
}
+void g_at_ppp_set_ipv6cp_info(GAtPPP *ppp, const char *local, const char *peer)
+{
+ struct in6_addr local_addr;
+ struct in6_addr peer_addr;
+
+ if (local)
+ inet_pton(AF_INET6, local, &local_addr);
+ else
+ memset(&local_addr, 0, sizeof(local_addr));
+
+ if (peer)
+ inet_pton(AF_INET6, peer, &peer_addr);
+ else
+ memset(&peer_addr, 0, sizeof(peer_addr));
+
+ ppp->ipv6cp = ipv6cp_new(ppp, (void *) &local_addr.s6_addr[8],
+ (void *) &peer_addr.s6_addr[8]);
+}
+
static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip)
{
GAtPPP *ppp;
diff --git a/gatchat/gatppp.h b/gatchat/gatppp.h
index b5a2234..9099d6b 100644
--- a/gatchat/gatppp.h
+++ b/gatchat/gatppp.h
@@ -37,6 +37,7 @@ typedef enum _GAtPPPDisconnectReason {
G_AT_PPP_REASON_UNKNOWN,
G_AT_PPP_REASON_AUTH_FAIL, /* Failed to authenticate */
G_AT_PPP_REASON_IPCP_FAIL, /* Failed to negotiate IPCP */
+ G_AT_PPP_REASON_IPV6CP_FAIL, /* Failed to negotiate IPV6CP */
G_AT_PPP_REASON_NET_FAIL, /* Failed to create tun */
G_AT_PPP_REASON_PEER_CLOSED, /* Peer initiated a close */
G_AT_PPP_REASON_LINK_DEAD, /* Link to the peer died */
@@ -81,6 +82,7 @@ void g_at_ppp_set_server_info(GAtPPP *ppp, const char *remote_ip,
void g_at_ppp_set_acfc_enabled(GAtPPP *ppp, gboolean enabled);
void g_at_ppp_set_pfc_enabled(GAtPPP *ppp, gboolean enabled);
+void g_at_ppp_set_ipv6cp_info(GAtPPP *ppp, const char *local, const char *peer);
#ifdef __cplusplus
}
diff --git a/gatchat/gsmdial.c b/gatchat/gsmdial.c
index be159eb..8f30309 100644
--- a/gatchat/gsmdial.c
+++ b/gatchat/gsmdial.c
@@ -59,6 +59,7 @@ static gchar *option_pppdump = NULL;
static gboolean option_bluetooth = FALSE;
static gboolean option_acfc = FALSE;
static gboolean option_pfc = FALSE;
+static gchar *option_ipv6 = NULL;
static GAtPPP *ppp;
static GAtChat *control;
@@ -372,6 +373,9 @@ static void connect_cb(gboolean ok, GAtResult *result, gpointer user_data)
if (option_pppdump)
g_at_ppp_set_recording(ppp, option_pppdump);
+ if (option_ipv6)
+ g_at_ppp_set_ipv6cp_info(ppp, option_ipv6, NULL);
+
g_at_ppp_set_credentials(ppp, option_username, option_password);
g_at_ppp_set_acfc_enabled(ppp, option_acfc);
@@ -687,6 +691,8 @@ static GOptionEntry options[] = {
"Use Protocol Field Compression" },
{ "acfc", 0, 0, G_OPTION_ARG_NONE, &option_acfc,
"Use Address & Control Field Compression" },
+ { "ipv6", '6', 0, G_OPTION_ARG_STRING, &option_ipv6,
+ "Specify IPv6 address" },
{ NULL },
};
diff --git a/gatchat/ppp.h b/gatchat/ppp.h
index a20fe85..5cb79f8 100644
--- a/gatchat/ppp.h
+++ b/gatchat/ppp.h
@@ -24,7 +24,9 @@
#define LCP_PROTOCOL 0xc021
#define CHAP_PROTOCOL 0xc223
#define IPCP_PROTO 0x8021
+#define IPV6CP_PROTO 0x8057
#define PPP_IP_PROTO 0x0021
+#define PPP_IPV6_PROTO 0x0057
#define MD5 5
#define DBG(p, fmt, arg...) do { \
@@ -44,6 +46,19 @@ struct ppp_header {
guint8 info[0];
} __attribute__((packed));
+struct eui64 {
+ union {
+ guint8 __e8[8];
+ guint16 __e16[4];
+ guint32 __e32[2];
+ } __u;
+#define e6_addr __u.__e8
+#define e6_addr16 __u.__e16
+#define e6_addr32 __u.__e32
+};
+
+#define EUI64_ANY_INIT { { { 0, 0, 0, 0, 0, 0, 0, 0 } } }
+
struct packed_short {
guint16 s;
} __attribute__((packed));
@@ -95,6 +110,11 @@ void ipcp_free(struct pppcp_data *data);
void ipcp_set_server_info(struct pppcp_data *ipcp, guint32 peer_addr,
guint32 dns1, guint32 dns2);
+/* IPv6 CP related functions */
+struct pppcp_data *ipv6cp_new(GAtPPP *ppp, const struct eui64 *local_addr,
+ const struct eui64 *peer_addr);
+void ipv6cp_free(struct pppcp_data *data);
+
/* CHAP related functions */
struct ppp_chap *ppp_chap_new(GAtPPP *ppp, guint8 method);
void ppp_chap_free(struct ppp_chap *chap);
@@ -120,6 +140,9 @@ void ppp_ipcp_up_notify(GAtPPP *ppp, const char *local, const char *peer,
const char *dns1, const char *dns2);
void ppp_ipcp_down_notify(GAtPPP *ppp);
void ppp_ipcp_finished_notify(GAtPPP *ppp);
+void ppp_ipv6cp_up_notify(GAtPPP *ppp, const char *local, const char *peer);
+void ppp_ipv6cp_down_notify(GAtPPP *ppp);
+void ppp_ipv6cp_finished_notify(GAtPPP *ppp);
void ppp_lcp_up_notify(GAtPPP *ppp);
void ppp_lcp_down_notify(GAtPPP *ppp);
void ppp_lcp_finished_notify(GAtPPP *ppp);
diff --git a/gatchat/ppp_ipv6cp.c b/gatchat/ppp_ipv6cp.c
new file mode 100644
index 0000000..b30d38a
--- /dev/null
+++ b/gatchat/ppp_ipv6cp.c
@@ -0,0 +1,306 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009-2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "gatppp.h"
+#include "ppp.h"
+
+#define IPV6CP_SUPPORTED_CODES ((1 << PPPCP_CODE_TYPE_CONFIGURE_REQUEST) | \
+ (1 << PPPCP_CODE_TYPE_CONFIGURE_ACK) | \
+ (1 << PPPCP_CODE_TYPE_CONFIGURE_NAK) | \
+ (1 << PPPCP_CODE_TYPE_CONFIGURE_REJECT) | \
+ (1 << PPPCP_CODE_TYPE_TERMINATE_REQUEST) | \
+ (1 << PPPCP_CODE_TYPE_TERMINATE_ACK) | \
+ (1 << PPPCP_CODE_TYPE_CODE_REJECT))
+
+enum ipv6cp_option_types {
+ IPV6CP_INTERFACE_ID = 1,
+ IPV6CP_COMPRESSION_PROTO = 2,
+};
+
+#define OPTIONS_COPY(_options, _len, _req, _type, _var, _opt_len) \
+ if (_req) { \
+ _options[_len] = _type; \
+ _options[_len + 1] = _opt_len + 2; \
+ memcpy(_options + _len + 2, _var, _opt_len); \
+ _len += _opt_len + 2; \
+ }
+
+/* We request only IPv6 Interface Id */
+#define MAX_IPV6CP_CONFIG_OPTION_SIZE 10
+#define MAX_IPV6CP_FAILURE 3
+
+struct ipv6cp_data {
+ guint8 options[MAX_IPV6CP_CONFIG_OPTION_SIZE];
+ guint16 options_len;
+ guint8 req_options;
+ struct eui64 local_addr;
+ struct eui64 peer_addr;
+};
+
+static const struct eui64 eui64_any = EUI64_ANY_INIT;
+
+static void ipv6cp_generate_config_options(struct ipv6cp_data *ipv6cp)
+{
+ guint16 len = 0;
+
+ OPTIONS_COPY(ipv6cp->options, len,
+ ipv6cp->req_options & IPV6CP_INTERFACE_ID,
+ IPV6CP_INTERFACE_ID, &ipv6cp->local_addr,
+ sizeof(ipv6cp->local_addr));
+
+ ipv6cp->options_len = len;
+}
+
+static void ipv6cp_reset_config_options(struct ipv6cp_data *ipv6cp)
+{
+ ipv6cp->req_options = IPV6CP_INTERFACE_ID;
+
+ ipv6cp_generate_config_options(ipv6cp);
+}
+
+static void ipv6cp_up(struct pppcp_data *pppcp)
+{
+ struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
+ struct in6_addr local_addr, peer_addr;
+ char local[INET6_ADDRSTRLEN], peer[INET6_ADDRSTRLEN];
+
+ memset(&local_addr, 0, sizeof(local_addr));
+ memcpy(&local_addr.s6_addr[8], &ipv6cp->local_addr,
+ sizeof(ipv6cp->local_addr));
+ memset(&peer_addr, 0, sizeof(peer_addr));
+ memcpy(&peer_addr.s6_addr[8], &ipv6cp->peer_addr,
+ sizeof(ipv6cp->peer_addr));
+ ppp_ipv6cp_up_notify(pppcp_get_ppp(pppcp),
+ inet_ntop(AF_INET6, &local_addr, local, INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &peer_addr, peer, INET6_ADDRSTRLEN));
+}
+
+static void ipv6cp_down(struct pppcp_data *pppcp)
+{
+ struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
+
+ ipv6cp_reset_config_options(ipv6cp);
+
+ pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
+ ppp_ipv6cp_down_notify(pppcp_get_ppp(pppcp));
+}
+
+static void ipv6cp_finished(struct pppcp_data *pppcp)
+{
+ ppp_ipv6cp_finished_notify(pppcp_get_ppp(pppcp));
+}
+
+static enum rcr_result ipv6cp_peer_addr_check(struct ipv6cp_data *ipv6cp,
+ const void *data)
+{
+ if (memcmp(&eui64_any, data, sizeof(eui64_any)) == 0)
+ return RCR_NAK;
+
+ return RCR_ACCEPT;
+}
+
+static enum rcr_result ipv6cp_rcr(struct pppcp_data *pppcp,
+ const struct pppcp_packet *packet,
+ guint8 **new_options, guint16 *new_len)
+{
+ struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
+ struct ppp_option_iter iter;
+ enum rcr_result result = RCR_ACCEPT;
+ guint16 len = 0, max_len = ntohs(packet->length) - 4;
+ guint8 *options = g_new0(guint8, max_len);
+ gboolean copy = TRUE;
+
+ ppp_option_iter_init(&iter, packet);
+
+ while (ppp_option_iter_next(&iter) == TRUE) {
+ guint8 type = ppp_option_iter_get_type(&iter);
+ const guint8 *data = ppp_option_iter_get_data(&iter);
+
+ switch (type) {
+ case IPV6CP_INTERFACE_ID:
+ if (result == RCR_ACCEPT) {
+
+ result = ipv6cp_peer_addr_check(ipv6cp, data);
+
+ if (result == RCR_ACCEPT)
+ memcpy(&ipv6cp->peer_addr, data,
+ sizeof(ipv6cp->peer_addr));
+ else
+ data = ipv6cp->peer_addr.e6_addr;
+ }
+ break;
+ default:
+ if (result == RCR_NAK) {
+ copy = FALSE;
+ } else if (result != RCR_REJECT) {
+ result = RCR_REJECT;
+ len = 0;
+ }
+ break;
+ }
+
+ OPTIONS_COPY(options, len, TRUE, type, data,
+ ppp_option_iter_get_length(&iter));
+ }
+
+ if (!len) {
+ g_free(options);
+ options = NULL;
+ }
+
+ *new_len = len;
+ *new_options = options;
+
+ return result;
+}
+
+static void ipv6cp_rca(struct pppcp_data *pppcp,
+ const struct pppcp_packet *packet)
+{
+ struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
+ struct ppp_option_iter iter;
+
+ ppp_option_iter_init(&iter, packet);
+
+ while (ppp_option_iter_next(&iter) == TRUE) {
+ const guint8 *data = ppp_option_iter_get_data(&iter);
+
+ switch (ppp_option_iter_get_type(&iter)) {
+ case IPV6CP_INTERFACE_ID:
+ if (memcmp(&ipv6cp->local_addr, data,
+ sizeof(ipv6cp->local_addr)))
+ DBG(pppcp_get_ppp(pppcp), "");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void ipv6cp_rcn_nak(struct pppcp_data *pppcp,
+ const struct pppcp_packet *packet)
+{
+ struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
+ struct ppp_option_iter iter;
+
+ ppp_option_iter_init(&iter, packet);
+
+ while (ppp_option_iter_next(&iter) == TRUE) {
+ const guint8 *data = ppp_option_iter_get_data(&iter);
+
+ switch (ppp_option_iter_get_type(&iter)) {
+ case IPV6CP_INTERFACE_ID:
+ memcpy(&ipv6cp->local_addr, data,
+ sizeof(ipv6cp->local_addr));
+ break;
+ default:
+ break;
+ }
+ }
+
+ ipv6cp_generate_config_options(ipv6cp);
+ pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
+}
+
+static void ipv6cp_rcn_rej(struct pppcp_data *pppcp,
+ const struct pppcp_packet *packet)
+{
+ struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
+ struct ppp_option_iter iter;
+
+ ppp_option_iter_init(&iter, packet);
+
+ while (ppp_option_iter_next(&iter) == TRUE) {
+ switch (ppp_option_iter_get_type(&iter)) {
+ case IPV6CP_INTERFACE_ID:
+ ipv6cp->req_options &= ~IPV6CP_INTERFACE_ID;
+ memset(&ipv6cp->local_addr, 0,
+ sizeof(ipv6cp->local_addr));
+ break;
+ default:
+ break;
+ }
+ }
+
+ ipv6cp_generate_config_options(ipv6cp);
+ pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
+}
+
+struct pppcp_proto ipv6cp_proto = {
+ .proto = IPV6CP_PROTO,
+ .name = "ipv6cp",
+ .supported_codes = IPV6CP_SUPPORTED_CODES,
+ .this_layer_up = ipv6cp_up,
+ .this_layer_down = ipv6cp_down,
+ .this_layer_finished = ipv6cp_finished,
+ .rca = ipv6cp_rca,
+ .rcn_nak = ipv6cp_rcn_nak,
+ .rcn_rej = ipv6cp_rcn_rej,
+ .rcr = ipv6cp_rcr,
+};
+
+struct pppcp_data *ipv6cp_new(GAtPPP *ppp, const struct eui64 *local_addr,
+ const struct eui64 *peer_addr)
+{
+ struct ipv6cp_data *ipv6cp;
+ struct pppcp_data *pppcp;
+
+ ipv6cp = g_try_new0(struct ipv6cp_data, 1);
+ if (ipv6cp == NULL)
+ return NULL;
+
+ pppcp = pppcp_new(ppp, &ipv6cp_proto, FALSE, MAX_IPV6CP_FAILURE);
+ if (pppcp == NULL) {
+ g_free(ipv6cp);
+ return NULL;
+ }
+
+ memcpy(&ipv6cp->local_addr, local_addr, sizeof(ipv6cp->local_addr));
+ memcpy(&ipv6cp->peer_addr, peer_addr, sizeof(ipv6cp->peer_addr));
+
+ pppcp_set_data(pppcp, ipv6cp);
+
+ ipv6cp_reset_config_options(ipv6cp);
+
+ pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
+
+ return pppcp;
+}
+
+void ipv6cp_free(struct pppcp_data *data)
+{
+ struct ipv6cp_data *ipv6cp = pppcp_get_data(data);
+
+ g_free(ipv6cp);
+ pppcp_free(data);
+}
diff --git a/gatchat/test-server.c b/gatchat/test-server.c
index 6f1d06d..59bbbe1 100644
--- a/gatchat/test-server.c
+++ b/gatchat/test-server.c
@@ -58,6 +58,8 @@ static int modem_creg = 0;
static int modem_cgreg = 0;
static int network_status = 4;
static int network_attach = 0;
+static const char *ipv6_local_addr = NULL;
+static const char *ipv6_peer_addr = NULL;
struct sock_server{
int server_sock;
@@ -176,6 +178,9 @@ static gboolean setup_ppp(GAtServer *server)
g_at_ppp_set_server_info(ppp, "192.168.1.2",
"10.10.10.10", "10.10.10.11");
+ if (ipv6_local_addr || ipv6_peer_addr)
+ g_at_ppp_set_ipv6cp_info(ppp, ipv6_local_addr, ipv6_peer_addr);
+
return TRUE;
}
@@ -1118,11 +1123,13 @@ static void usage(void)
{
g_print("test-server - AT Server testing\n"
"Usage:\n");
- g_print("\ttest-server [-t type]\n");
+ g_print("\ttest-server [-t type] [-6 addr]\n");
g_print("Types:\n"
"\t0: Pseudo TTY port (default)\n"
"\t1: TCP sock at port 12346)\n"
"\t2: Unix sock at ./server_sock\n");
+ g_print("-l\tSpecify local IPv6 address\n");
+ g_print("-p\tSpecify peer IPv6 address\n");
}
int main(int argc, char **argv)
@@ -1130,11 +1137,17 @@ int main(int argc, char **argv)
int opt, signal_source;
int type = 0;
- while ((opt = getopt(argc, argv, "ht:")) != EOF) {
+ while ((opt = getopt(argc, argv, "hl:p:t:")) != EOF) {
switch (opt) {
case 't':
type = atoi(optarg);
break;
+ case 'l':
+ ipv6_local_addr = optarg;
+ break;
+ case 'p':
+ ipv6_peer_addr = optarg;
+ break;
case 'h':
usage();
exit(1);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 1/1] gatchat: Add IPv6 CP support
2011-10-26 14:20 ` [PATCH 1/1] gatchat: Add " Oleg Zhurakivskyy
@ 2011-10-31 7:43 ` Denis Kenzior
2011-11-02 10:29 ` Oleg Zhurakivskyy
0 siblings, 1 reply; 4+ messages in thread
From: Denis Kenzior @ 2011-10-31 7:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 21316 bytes --]
Hi Oleg,
On 10/26/2011 09:20 AM, Oleg Zhurakivskyy wrote:
> ---
> Makefile.am | 2 +-
> gatchat/gatppp.c | 58 +++++++++-
> gatchat/gatppp.h | 2 +
> gatchat/gsmdial.c | 6 +
> gatchat/ppp.h | 23 ++++
> gatchat/ppp_ipv6cp.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++
> gatchat/test-server.c | 17 +++-
> 7 files changed, 410 insertions(+), 4 deletions(-)
> create mode 100644 gatchat/ppp_ipv6cp.c
>
This looks like a good start. However, please separate this patch into
several, like this:
- One adding the bulk of IPv6CP protocol
- One for hooks in gatppp itself & ipv6cp
- One for gsmdial
- One for test-server.
> diff --git a/Makefile.am b/Makefile.am
> index 83b7737..44fdfff 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -76,7 +76,7 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
> gatchat/ppp.h gatchat/ppp_cp.h \
> gatchat/ppp_cp.c gatchat/ppp_lcp.c \
> gatchat/ppp_auth.c gatchat/ppp_net.c \
> - gatchat/ppp_ipcp.c
> + gatchat/ppp_ipcp.c gatchat/ppp_ipv6cp.c
>
> gisi_sources = gisi/client.c gisi/client.h gisi/common.h \
> gisi/iter.c gisi/iter.h \
> diff --git a/gatchat/gatppp.c b/gatchat/gatppp.c
> index f767f4a..41f9dff 100644
> --- a/gatchat/gatppp.c
> +++ b/gatchat/gatppp.c
> @@ -62,6 +62,7 @@ struct _GAtPPP {
> enum ppp_phase phase;
> struct pppcp_data *lcp;
> struct pppcp_data *ipcp;
> + struct pppcp_data *ipv6cp;
> struct ppp_net *net;
> struct ppp_chap *chap;
> GAtHDLC *hdlc;
> @@ -157,7 +158,8 @@ static inline gboolean ppp_drop_packet(GAtPPP *ppp, guint16 protocol)
> return TRUE;
> case PPP_PHASE_NETWORK:
> if (protocol != LCP_PROTOCOL && protocol != CHAP_PROTOCOL &&
> - protocol != IPCP_PROTO)
> + protocol != IPCP_PROTO &&
> + protocol != IPV6CP_PROTO)
> return TRUE;
> break;
> case PPP_PHASE_LINK_UP:
> @@ -222,6 +224,10 @@ static void ppp_receive(const unsigned char *buf, gsize len, void *data)
> case IPCP_PROTO:
> pppcp_process_packet(ppp->ipcp, packet, len - offset);
> break;
> + case IPV6CP_PROTO:
> + if (ppp->ipv6cp)
> + pppcp_process_packet(ppp->ipv6cp, packet, len - offset);
> + break;
> case CHAP_PROTOCOL:
> if (ppp->chap) {
> ppp_chap_process_packet(ppp->chap, packet,
> @@ -381,6 +387,13 @@ void ppp_auth_notify(GAtPPP *ppp, gboolean success)
>
> ppp_enter_phase(ppp, PPP_PHASE_NETWORK);
>
> + /* Send UP & OPEN events to the IPv6 CP */
> + if (ppp->ipv6cp) {
> + pppcp_signal_open(ppp->ipv6cp);
> + pppcp_signal_up(ppp->ipv6cp);
> + return;
> + }
> +
Can IPV6CP and IPCP co-exist? In theory there is such a concept as
dual-stack contexts, however I don't know whether any modem in existence
does this with PPP.
> /* Send UP & OPEN events to the IPCP layer */
> pppcp_signal_open(ppp->ipcp);
> pppcp_signal_up(ppp->ipcp);
> @@ -435,6 +448,28 @@ void ppp_ipcp_finished_notify(GAtPPP *ppp)
> pppcp_signal_close(ppp->lcp);
> }
>
> +void ppp_ipv6cp_up_notify(GAtPPP *ppp, const char *local, const char *peer)
> +{
> + DBG(ppp, "local: %s, peer: %s", local, peer);
> +}
> +
> +void ppp_ipv6cp_down_notify(GAtPPP *ppp)
> +{
> + DBG(ppp, "");
> +}
> +
> +void ppp_ipv6cp_finished_notify(GAtPPP *ppp)
> +{
> + DBG(ppp, "");
> +
> + if (ppp->phase != PPP_PHASE_NETWORK)
> + return;
> +
> + ppp->disconnect_reason = G_AT_PPP_REASON_IPV6CP_FAIL;
> + pppcp_signal_close(ppp->ipv6cp);
> + pppcp_signal_close(ppp->lcp);
> +}
> +
> void ppp_lcp_up_notify(GAtPPP *ppp)
> {
> /* Wait for the peer to send us a challenge if we expect auth */
> @@ -732,6 +767,8 @@ void g_at_ppp_unref(GAtPPP *ppp)
>
> lcp_free(ppp->lcp);
> ipcp_free(ppp->ipcp);
> + if (ppp->ipv6cp)
> + ipv6cp_free(ppp->ipv6cp);
>
> if (ppp->ppp_dead_source) {
> g_source_remove(ppp->ppp_dead_source);
> @@ -772,6 +809,25 @@ void g_at_ppp_set_pfc_enabled(GAtPPP *ppp, gboolean enabled)
> lcp_set_pfc_enabled(ppp->lcp, enabled);
> }
>
> +void g_at_ppp_set_ipv6cp_info(GAtPPP *ppp, const char *local, const char *peer)
> +{
> + struct in6_addr local_addr;
> + struct in6_addr peer_addr;
> +
> + if (local)
> + inet_pton(AF_INET6, local, &local_addr);
> + else
> + memset(&local_addr, 0, sizeof(local_addr));
> +
What if inet_pton fails?
> + if (peer)
> + inet_pton(AF_INET6, peer, &peer_addr);
> + else
> + memset(&peer_addr, 0, sizeof(peer_addr));
> +
> + ppp->ipv6cp = ipv6cp_new(ppp, (void *) &local_addr.s6_addr[8],
> + (void *) &peer_addr.s6_addr[8]);
> +}
> +
> static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip)
> {
> GAtPPP *ppp;
> diff --git a/gatchat/gatppp.h b/gatchat/gatppp.h
> index b5a2234..9099d6b 100644
> --- a/gatchat/gatppp.h
> +++ b/gatchat/gatppp.h
> @@ -37,6 +37,7 @@ typedef enum _GAtPPPDisconnectReason {
> G_AT_PPP_REASON_UNKNOWN,
> G_AT_PPP_REASON_AUTH_FAIL, /* Failed to authenticate */
> G_AT_PPP_REASON_IPCP_FAIL, /* Failed to negotiate IPCP */
> + G_AT_PPP_REASON_IPV6CP_FAIL, /* Failed to negotiate IPV6CP */
> G_AT_PPP_REASON_NET_FAIL, /* Failed to create tun */
> G_AT_PPP_REASON_PEER_CLOSED, /* Peer initiated a close */
> G_AT_PPP_REASON_LINK_DEAD, /* Link to the peer died */
> @@ -81,6 +82,7 @@ void g_at_ppp_set_server_info(GAtPPP *ppp, const char *remote_ip,
>
> void g_at_ppp_set_acfc_enabled(GAtPPP *ppp, gboolean enabled);
> void g_at_ppp_set_pfc_enabled(GAtPPP *ppp, gboolean enabled);
> +void g_at_ppp_set_ipv6cp_info(GAtPPP *ppp, const char *local, const char *peer);
>
> #ifdef __cplusplus
> }
> diff --git a/gatchat/gsmdial.c b/gatchat/gsmdial.c
> index be159eb..8f30309 100644
> --- a/gatchat/gsmdial.c
> +++ b/gatchat/gsmdial.c
> @@ -59,6 +59,7 @@ static gchar *option_pppdump = NULL;
> static gboolean option_bluetooth = FALSE;
> static gboolean option_acfc = FALSE;
> static gboolean option_pfc = FALSE;
> +static gchar *option_ipv6 = NULL;
>
> static GAtPPP *ppp;
> static GAtChat *control;
> @@ -372,6 +373,9 @@ static void connect_cb(gboolean ok, GAtResult *result, gpointer user_data)
> if (option_pppdump)
> g_at_ppp_set_recording(ppp, option_pppdump);
>
> + if (option_ipv6)
> + g_at_ppp_set_ipv6cp_info(ppp, option_ipv6, NULL);
> +
> g_at_ppp_set_credentials(ppp, option_username, option_password);
>
> g_at_ppp_set_acfc_enabled(ppp, option_acfc);
> @@ -687,6 +691,8 @@ static GOptionEntry options[] = {
> "Use Protocol Field Compression" },
> { "acfc", 0, 0, G_OPTION_ARG_NONE, &option_acfc,
> "Use Address & Control Field Compression" },
> + { "ipv6", '6', 0, G_OPTION_ARG_STRING, &option_ipv6,
> + "Specify IPv6 address" },
> { NULL },
> };
>
> diff --git a/gatchat/ppp.h b/gatchat/ppp.h
> index a20fe85..5cb79f8 100644
> --- a/gatchat/ppp.h
> +++ b/gatchat/ppp.h
> @@ -24,7 +24,9 @@
> #define LCP_PROTOCOL 0xc021
> #define CHAP_PROTOCOL 0xc223
> #define IPCP_PROTO 0x8021
> +#define IPV6CP_PROTO 0x8057
> #define PPP_IP_PROTO 0x0021
> +#define PPP_IPV6_PROTO 0x0057
> #define MD5 5
>
> #define DBG(p, fmt, arg...) do { \
> @@ -44,6 +46,19 @@ struct ppp_header {
> guint8 info[0];
> } __attribute__((packed));
>
> +struct eui64 {
> + union {
> + guint8 __e8[8];
> + guint16 __e16[4];
> + guint32 __e32[2];
> + } __u;
> +#define e6_addr __u.__e8
> +#define e6_addr16 __u.__e16
> +#define e6_addr32 __u.__e32
> +};
I really don't like this actually. I would either simply use an
unsigned char[8] array or use guint64.
> +
> +#define EUI64_ANY_INIT { { { 0, 0, 0, 0, 0, 0, 0, 0 } } }
> +
This initializer doesn't seem necessary, and if it was, then it doesn't
belong here, but inside ipv6cp.c since this is the only place using it.
> struct packed_short {
> guint16 s;
> } __attribute__((packed));
> @@ -95,6 +110,11 @@ void ipcp_free(struct pppcp_data *data);
> void ipcp_set_server_info(struct pppcp_data *ipcp, guint32 peer_addr,
> guint32 dns1, guint32 dns2);
>
> +/* IPv6 CP related functions */
> +struct pppcp_data *ipv6cp_new(GAtPPP *ppp, const struct eui64 *local_addr,
> + const struct eui64 *peer_addr);
Thinking more about it, why don't you make this function take const char
* arguments instead, and hide away all the nasty details inside
ipv6cp.c? This way all these funky structs are hidden away in the
implementation, and you can use whatever is the most convenient.
> +void ipv6cp_free(struct pppcp_data *data);
> +
> /* CHAP related functions */
> struct ppp_chap *ppp_chap_new(GAtPPP *ppp, guint8 method);
> void ppp_chap_free(struct ppp_chap *chap);
> @@ -120,6 +140,9 @@ void ppp_ipcp_up_notify(GAtPPP *ppp, const char *local, const char *peer,
> const char *dns1, const char *dns2);
> void ppp_ipcp_down_notify(GAtPPP *ppp);
> void ppp_ipcp_finished_notify(GAtPPP *ppp);
> +void ppp_ipv6cp_up_notify(GAtPPP *ppp, const char *local, const char *peer);
> +void ppp_ipv6cp_down_notify(GAtPPP *ppp);
> +void ppp_ipv6cp_finished_notify(GAtPPP *ppp);
> void ppp_lcp_up_notify(GAtPPP *ppp);
> void ppp_lcp_down_notify(GAtPPP *ppp);
> void ppp_lcp_finished_notify(GAtPPP *ppp);
> diff --git a/gatchat/ppp_ipv6cp.c b/gatchat/ppp_ipv6cp.c
> new file mode 100644
> index 0000000..b30d38a
> --- /dev/null
> +++ b/gatchat/ppp_ipv6cp.c
> @@ -0,0 +1,306 @@
> +/*
> + *
> + * oFono - Open Source Telephony
> + *
> + * Copyright (C) 2009-2011 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <arpa/inet.h>
> +#include <sys/socket.h>
> +#include <netinet/in.h>
> +
> +#include <string.h>
> +
> +#include <glib.h>
> +
> +#include "gatppp.h"
> +#include "ppp.h"
> +
> +#define IPV6CP_SUPPORTED_CODES ((1 << PPPCP_CODE_TYPE_CONFIGURE_REQUEST) | \
> + (1 << PPPCP_CODE_TYPE_CONFIGURE_ACK) | \
> + (1 << PPPCP_CODE_TYPE_CONFIGURE_NAK) | \
> + (1 << PPPCP_CODE_TYPE_CONFIGURE_REJECT) | \
> + (1 << PPPCP_CODE_TYPE_TERMINATE_REQUEST) | \
> + (1 << PPPCP_CODE_TYPE_TERMINATE_ACK) | \
> + (1 << PPPCP_CODE_TYPE_CODE_REJECT))
> +
> +enum ipv6cp_option_types {
> + IPV6CP_INTERFACE_ID = 1,
> + IPV6CP_COMPRESSION_PROTO = 2,
The latest RFC 5072 doesn't even have this option, so you can probably
get rid of it.
> +};
> +
> +#define OPTIONS_COPY(_options, _len, _req, _type, _var, _opt_len) \
> + if (_req) { \
> + _options[_len] = _type; \
> + _options[_len + 1] = _opt_len + 2; \
> + memcpy(_options + _len + 2, _var, _opt_len); \
> + _len += _opt_len + 2; \
> + }
> +
> +/* We request only IPv6 Interface Id */
> +#define MAX_IPV6CP_CONFIG_OPTION_SIZE 10
> +#define MAX_IPV6CP_FAILURE 3
> +
> +struct ipv6cp_data {
> + guint8 options[MAX_IPV6CP_CONFIG_OPTION_SIZE];
> + guint16 options_len;
> + guint8 req_options;
> + struct eui64 local_addr;
> + struct eui64 peer_addr;
> +};
> +
> +static const struct eui64 eui64_any = EUI64_ANY_INIT;
> +
> +static void ipv6cp_generate_config_options(struct ipv6cp_data *ipv6cp)
> +{
> + guint16 len = 0;
> +
> + OPTIONS_COPY(ipv6cp->options, len,
> + ipv6cp->req_options & IPV6CP_INTERFACE_ID,
> + IPV6CP_INTERFACE_ID, &ipv6cp->local_addr,
> + sizeof(ipv6cp->local_addr));
> +
> + ipv6cp->options_len = len;
> +}
> +
> +static void ipv6cp_reset_config_options(struct ipv6cp_data *ipv6cp)
> +{
> + ipv6cp->req_options = IPV6CP_INTERFACE_ID;
> +
> + ipv6cp_generate_config_options(ipv6cp);
> +}
> +
> +static void ipv6cp_up(struct pppcp_data *pppcp)
> +{
> + struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
> + struct in6_addr local_addr, peer_addr;
> + char local[INET6_ADDRSTRLEN], peer[INET6_ADDRSTRLEN];
> +
> + memset(&local_addr, 0, sizeof(local_addr));
> + memcpy(&local_addr.s6_addr[8], &ipv6cp->local_addr,
> + sizeof(ipv6cp->local_addr));
> + memset(&peer_addr, 0, sizeof(peer_addr));
> + memcpy(&peer_addr.s6_addr[8], &ipv6cp->peer_addr,
> + sizeof(ipv6cp->peer_addr));
> + ppp_ipv6cp_up_notify(pppcp_get_ppp(pppcp),
> + inet_ntop(AF_INET6, &local_addr, local, INET6_ADDRSTRLEN),
> + inet_ntop(AF_INET6, &peer_addr, peer, INET6_ADDRSTRLEN));
> +}
> +
> +static void ipv6cp_down(struct pppcp_data *pppcp)
> +{
> + struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
> +
> + ipv6cp_reset_config_options(ipv6cp);
> +
> + pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
> + ppp_ipv6cp_down_notify(pppcp_get_ppp(pppcp));
> +}
> +
> +static void ipv6cp_finished(struct pppcp_data *pppcp)
> +{
> + ppp_ipv6cp_finished_notify(pppcp_get_ppp(pppcp));
> +}
> +
> +static enum rcr_result ipv6cp_peer_addr_check(struct ipv6cp_data *ipv6cp,
> + const void *data)
> +{
> + if (memcmp(&eui64_any, data, sizeof(eui64_any)) == 0)
> + return RCR_NAK;
> +
If we're playing the server role, then we might want to NAK non-zero
peer interface ids as well.
> + return RCR_ACCEPT;
> +}
> +
> +static enum rcr_result ipv6cp_rcr(struct pppcp_data *pppcp,
> + const struct pppcp_packet *packet,
> + guint8 **new_options, guint16 *new_len)
> +{
> + struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
> + struct ppp_option_iter iter;
> + enum rcr_result result = RCR_ACCEPT;
> + guint16 len = 0, max_len = ntohs(packet->length) - 4;
> + guint8 *options = g_new0(guint8, max_len);
> + gboolean copy = TRUE;
> +
> + ppp_option_iter_init(&iter, packet);
> +
> + while (ppp_option_iter_next(&iter) == TRUE) {
> + guint8 type = ppp_option_iter_get_type(&iter);
> + const guint8 *data = ppp_option_iter_get_data(&iter);
> +
> + switch (type) {
> + case IPV6CP_INTERFACE_ID:
> + if (result == RCR_ACCEPT) {
> +
> + result = ipv6cp_peer_addr_check(ipv6cp, data);
> +
> + if (result == RCR_ACCEPT)
> + memcpy(&ipv6cp->peer_addr, data,
> + sizeof(ipv6cp->peer_addr));
> + else
> + data = ipv6cp->peer_addr.e6_addr;
> + }
> + break;
> + default:
> + if (result == RCR_NAK) {
> + copy = FALSE;
> + } else if (result != RCR_REJECT) {
> + result = RCR_REJECT;
> + len = 0;
> + }
> + break;
> + }
> +
> + OPTIONS_COPY(options, len, TRUE, type, data,
> + ppp_option_iter_get_length(&iter));
> + }
> +
> + if (!len) {
> + g_free(options);
> + options = NULL;
> + }
> +
> + *new_len = len;
> + *new_options = options;
> +
Is there a particular reason you did not structure this function in the
same manner as ipcp_server/client_rcr? They are pretty much optimized
with no allocations on the fast (non-reject) path and I'd like to have
consistency in the code.
> + return result;
> +}
> +
> +static void ipv6cp_rca(struct pppcp_data *pppcp,
> + const struct pppcp_packet *packet)
> +{
> + struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
> + struct ppp_option_iter iter;
> +
> + ppp_option_iter_init(&iter, packet);
> +
> + while (ppp_option_iter_next(&iter) == TRUE) {
> + const guint8 *data = ppp_option_iter_get_data(&iter);
> +
> + switch (ppp_option_iter_get_type(&iter)) {
> + case IPV6CP_INTERFACE_ID:
> + if (memcmp(&ipv6cp->local_addr, data,
> + sizeof(ipv6cp->local_addr)))
> + DBG(pppcp_get_ppp(pppcp), "");
> + break;
> + default:
> + break;
> + }
> + }
> +}
> +
> +static void ipv6cp_rcn_nak(struct pppcp_data *pppcp,
> + const struct pppcp_packet *packet)
> +{
> + struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
> + struct ppp_option_iter iter;
> +
> + ppp_option_iter_init(&iter, packet);
> +
We have to be a bit careful here, if we are playing the server role then
we should not let the client dictate our interface ID. The reason being
that e.g. ConnMan might be allocating our interface ids from its own
pool and we can't really change it at this point.
> + while (ppp_option_iter_next(&iter) == TRUE) {
> + const guint8 *data = ppp_option_iter_get_data(&iter);
> +
> + switch (ppp_option_iter_get_type(&iter)) {
> + case IPV6CP_INTERFACE_ID:
> + memcpy(&ipv6cp->local_addr, data,
> + sizeof(ipv6cp->local_addr));
You might also want to make sure to set the flag to request the
interface id, though this is more of a problem with IPCP.
> + break;
> + default:
> + break;
> + }
> + }
> +
> + ipv6cp_generate_config_options(ipv6cp);
> + pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
> +}
> +
> +static void ipv6cp_rcn_rej(struct pppcp_data *pppcp,
> + const struct pppcp_packet *packet)
> +{
> + struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
> + struct ppp_option_iter iter;
> +
> + ppp_option_iter_init(&iter, packet);
> +
> + while (ppp_option_iter_next(&iter) == TRUE) {
> + switch (ppp_option_iter_get_type(&iter)) {
> + case IPV6CP_INTERFACE_ID:
> + ipv6cp->req_options &= ~IPV6CP_INTERFACE_ID;
> + memset(&ipv6cp->local_addr, 0,
> + sizeof(ipv6cp->local_addr));
This means that the peer refused to configure this option, it doesn't
mean that our idea of our interface (e.g. if we're the server) should be
reset...
> + break;
> + default:
> + break;
> + }
> + }
> +
> + ipv6cp_generate_config_options(ipv6cp);
> + pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
> +}
> +
> +struct pppcp_proto ipv6cp_proto = {
> + .proto = IPV6CP_PROTO,
> + .name = "ipv6cp",
> + .supported_codes = IPV6CP_SUPPORTED_CODES,
> + .this_layer_up = ipv6cp_up,
> + .this_layer_down = ipv6cp_down,
> + .this_layer_finished = ipv6cp_finished,
> + .rca = ipv6cp_rca,
> + .rcn_nak = ipv6cp_rcn_nak,
> + .rcn_rej = ipv6cp_rcn_rej,
> + .rcr = ipv6cp_rcr,
> +};
> +
> +struct pppcp_data *ipv6cp_new(GAtPPP *ppp, const struct eui64 *local_addr,
> + const struct eui64 *peer_addr)
> +{
> + struct ipv6cp_data *ipv6cp;
> + struct pppcp_data *pppcp;
> +
> + ipv6cp = g_try_new0(struct ipv6cp_data, 1);
> + if (ipv6cp == NULL)
> + return NULL;
> +
> + pppcp = pppcp_new(ppp, &ipv6cp_proto, FALSE, MAX_IPV6CP_FAILURE);
> + if (pppcp == NULL) {
> + g_free(ipv6cp);
> + return NULL;
> + }
> +
> + memcpy(&ipv6cp->local_addr, local_addr, sizeof(ipv6cp->local_addr));
> + memcpy(&ipv6cp->peer_addr, peer_addr, sizeof(ipv6cp->peer_addr));
> +
> + pppcp_set_data(pppcp, ipv6cp);
> +
> + ipv6cp_reset_config_options(ipv6cp);
> +
> + pppcp_set_local_options(pppcp, ipv6cp->options, ipv6cp->options_len);
> +
> + return pppcp;
> +}
> +
> +void ipv6cp_free(struct pppcp_data *data)
> +{
> + struct ipv6cp_data *ipv6cp = pppcp_get_data(data);
> +
> + g_free(ipv6cp);
> + pppcp_free(data);
> +}
> diff --git a/gatchat/test-server.c b/gatchat/test-server.c
> index 6f1d06d..59bbbe1 100644
> --- a/gatchat/test-server.c
> +++ b/gatchat/test-server.c
> @@ -58,6 +58,8 @@ static int modem_creg = 0;
> static int modem_cgreg = 0;
> static int network_status = 4;
> static int network_attach = 0;
> +static const char *ipv6_local_addr = NULL;
> +static const char *ipv6_peer_addr = NULL;
>
> struct sock_server{
> int server_sock;
> @@ -176,6 +178,9 @@ static gboolean setup_ppp(GAtServer *server)
> g_at_ppp_set_server_info(ppp, "192.168.1.2",
> "10.10.10.10", "10.10.10.11");
>
> + if (ipv6_local_addr || ipv6_peer_addr)
> + g_at_ppp_set_ipv6cp_info(ppp, ipv6_local_addr, ipv6_peer_addr);
> +
> return TRUE;
> }
>
> @@ -1118,11 +1123,13 @@ static void usage(void)
> {
> g_print("test-server - AT Server testing\n"
> "Usage:\n");
> - g_print("\ttest-server [-t type]\n");
> + g_print("\ttest-server [-t type] [-6 addr]\n");
Hm, this message makes no sense.
> g_print("Types:\n"
> "\t0: Pseudo TTY port (default)\n"
> "\t1: TCP sock at port 12346)\n"
> "\t2: Unix sock at ./server_sock\n");
> + g_print("-l\tSpecify local IPv6 address\n");
> + g_print("-p\tSpecify peer IPv6 address\n");
> }
>
> int main(int argc, char **argv)
> @@ -1130,11 +1137,17 @@ int main(int argc, char **argv)
> int opt, signal_source;
> int type = 0;
>
> - while ((opt = getopt(argc, argv, "ht:")) != EOF) {
> + while ((opt = getopt(argc, argv, "hl:p:t:")) != EOF) {
> switch (opt) {
> case 't':
> type = atoi(optarg);
> break;
> + case 'l':
> + ipv6_local_addr = optarg;
> + break;
> + case 'p':
> + ipv6_peer_addr = optarg;
> + break;
> case 'h':
> usage();
> exit(1);
Regards,
-Denis
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/1] gatchat: Add IPv6 CP support
2011-10-31 7:43 ` Denis Kenzior
@ 2011-11-02 10:29 ` Oleg Zhurakivskyy
0 siblings, 0 replies; 4+ messages in thread
From: Oleg Zhurakivskyy @ 2011-11-02 10:29 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 4819 bytes --]
Hello Denis,
On 10/31/2011 09:43 AM, Denis Kenzior wrote:
> This looks like a good start. However, please separate this patch into
> several, like this:
>
> - One adding the bulk of IPv6CP protocol
> - One for hooks in gatppp itself& ipv6cp
> - One for gsmdial
> - One for test-server.
Sure, will structure like that.
> Can IPV6CP and IPCP co-exist? In theory there is such a concept as
> dual-stack contexts, however I don't know whether any modem in existence
> does this with PPP.
Incidentally, I was thinking about this too. I already made IPCP and IPv6CP to
co-exist, will post it together with corrections in the next version.
>> +void g_at_ppp_set_ipv6cp_info(GAtPPP *ppp, const char *local, const char *peer)
>> +{
>> + struct in6_addr local_addr;
>> + struct in6_addr peer_addr;
>> +
>> + if (local)
>> + inet_pton(AF_INET6, local,&local_addr);
>> + else
>> + memset(&local_addr, 0, sizeof(local_addr));
>> +
>
> What if inet_pton fails?
Sure, I will improve this.
>> +struct eui64 {
[...]
>> +};
>
> I really don't like this actually. I would either simply use an
> unsigned char[8] array or use guint64.
Sure, simple guint8[8] will do.
>> +struct pppcp_data *ipv6cp_new(GAtPPP *ppp, const struct eui64 *local_addr,
>> + const struct eui64 *peer_addr);
>
> Thinking more about it, why don't you make this function take const char
> * arguments instead, and hide away all the nasty details inside
> ipv6cp.c? This way all these funky structs are hidden away in the
> implementation, and you can use whatever is the most convenient.
Good point, I will correct.
>> +enum ipv6cp_option_types {
>> + IPV6CP_INTERFACE_ID = 1,
>> + IPV6CP_COMPRESSION_PROTO = 2,
>
> The latest RFC 5072 doesn't even have this option, so you can probably
> get rid of it.
OK.
>> +static enum rcr_result ipv6cp_peer_addr_check(struct ipv6cp_data *ipv6cp,
>> + const void *data)
>> +{
>> + if (memcmp(&eui64_any, data, sizeof(eui64_any)) == 0)
>> + return RCR_NAK;
>> +
>
> If we're playing the server role, then we might want to NAK non-zero
> peer interface ids as well.
OK.
>> +static enum rcr_result ipv6cp_rcr(struct pppcp_data *pppcp,
>> + const struct pppcp_packet *packet,
>> + guint8 **new_options, guint16 *new_len)
>
> Is there a particular reason you did not structure this function in the
> same manner as ipcp_server/client_rcr? They are pretty much optimized
> with no allocations on the fast (non-reject) path and I'd like to have
> consistency in the code.
I tried to simplify this a bit, and to get rid of the client-server separation,
if possible. I missed the point that the fast path is optimized.
Anyway, thanks for the explanation, I will separate into client and server and
make sure there aren't extra allocations on the fast path.
>> +static void ipv6cp_rcn_nak(struct pppcp_data *pppcp,
>> + const struct pppcp_packet *packet)
>> +{
>> + struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
>> + struct ppp_option_iter iter;
>> +
>> + ppp_option_iter_init(&iter, packet);
>> +
>
> We have to be a bit careful here, if we are playing the server role then
> we should not let the client dictate our interface ID. The reason being
> that e.g. ConnMan might be allocating our interface ids from its own
> pool and we can't really change it at this point.
OK, thanks for the input here, I will take this into account.
>> + while (ppp_option_iter_next(&iter) == TRUE) {
>> + const guint8 *data = ppp_option_iter_get_data(&iter);
>> +
>> + switch (ppp_option_iter_get_type(&iter)) {
>> + case IPV6CP_INTERFACE_ID:
>> + memcpy(&ipv6cp->local_addr, data,
>> + sizeof(ipv6cp->local_addr));
>
> You might also want to make sure to set the flag to request the
> interface id, though this is more of a problem with IPCP.
OK, will check this.
>> + while (ppp_option_iter_next(&iter) == TRUE) {
>> + switch (ppp_option_iter_get_type(&iter)) {
>> + case IPV6CP_INTERFACE_ID:
>> + ipv6cp->req_options&= ~IPV6CP_INTERFACE_ID;
>> + memset(&ipv6cp->local_addr, 0,
>> + sizeof(ipv6cp->local_addr));
>
> This means that the peer refused to configure this option, it doesn't
> mean that our idea of our interface (e.g. if we're the server) should be
> reset...
Will check this too.
>> + g_print("\ttest-server [-t type] [-6 addr]\n");
>
> Hm, this message makes no sense.
This was added for testing purposes, just in order to test if both ends can
exchange the IDs. I will remove it, if it's not necessary.
Thanks for the comments, I will prepare and send another set.
Regards,
Oleg
--
Intel Finland Oy
Registered Address: PL 281, 00181 Helsinki
Business Identity Code: 0357606 - 4
Domiciled in Helsinki
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2011-11-02 10:29 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-26 14:20 [PATCH 0/1] Initial patches for gatchat IPv6 CP support Oleg Zhurakivskyy
2011-10-26 14:20 ` [PATCH 1/1] gatchat: Add " Oleg Zhurakivskyy
2011-10-31 7:43 ` Denis Kenzior
2011-11-02 10:29 ` Oleg Zhurakivskyy
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.