---
gatchat/gatppp.c | 189 ++++++++++++++++++++++++++++++++++++++++++++-----
gatchat/gatppp.h | 17 +++++
gatchat/ppp.h | 8 ++-
gatchat/ppp_ipv6cp.c | 54 ++++++++++-----
4 files changed, 229 insertions(+), 39 deletions(-)
diff --git a/gatchat/gatppp.c b/gatchat/gatppp.c
index f767f4a..be90e81 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;
@@ -85,6 +86,7 @@ struct _GAtPPP {
gboolean suspended;
gboolean xmit_acfc;
gboolean xmit_pfc;
+ guint8 proto;
};
void ppp_debug(GAtPPP *ppp, const char *str)
@@ -157,7 +159,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:
@@ -220,19 +223,31 @@ static void ppp_receive(const unsigned char *buf, gsize len, void
*data)
pppcp_process_packet(ppp->lcp, packet, len - offset);
break;
case IPCP_PROTO:
+ if (ppp->ipcp == NULL)
+ goto reject;
+
pppcp_process_packet(ppp->ipcp, packet, len - offset);
break;
+ case IPV6CP_PROTO:
+ if (ppp->ipv6cp == NULL)
+ goto reject;
+
+ pppcp_process_packet(ppp->ipv6cp, packet, len - offset);
+ break;
case CHAP_PROTOCOL:
- if (ppp->chap) {
- ppp_chap_process_packet(ppp->chap, packet,
- len - offset);
- break;
- }
- /* fall through */
+ if (ppp->chap == NULL)
+ goto reject;
+
+ ppp_chap_process_packet(ppp->chap, packet, len - offset);
+ break;
default:
- pppcp_send_protocol_reject(ppp->lcp, buf, len);
break;
};
+
+ return;
+
+reject:
+ pppcp_send_protocol_reject(ppp->lcp, buf, len);
}
static void ppp_send_lcp_frame(GAtPPP *ppp, guint8 *packet, guint infolen)
@@ -381,9 +396,17 @@ 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);
+ }
+
/* Send UP & OPEN events to the IPCP layer */
- pppcp_signal_open(ppp->ipcp);
- pppcp_signal_up(ppp->ipcp);
+ if (ppp->ipcp) {
+ pppcp_signal_open(ppp->ipcp);
+ pppcp_signal_up(ppp->ipcp);
+ }
}
void ppp_ipcp_up_notify(GAtPPP *ppp, const char *local, const char *peer,
@@ -431,10 +454,42 @@ void ppp_ipcp_finished_notify(GAtPPP *ppp)
/* Our IPCP parameter negotiation failed */
ppp->disconnect_reason = G_AT_PPP_REASON_IPCP_FAIL;
+
+ if (ppp->ipv6cp)
+ pppcp_signal_close(ppp->ipv6cp);
+
pppcp_signal_close(ppp->ipcp);
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);
+
+ ppp_enter_phase(ppp, PPP_PHASE_LINK_UP);
+}
+
+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;
+
+ if (ppp->ipcp)
+ pppcp_signal_close(ppp->ipcp);
+
+ 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 */
@@ -449,8 +504,14 @@ void ppp_lcp_up_notify(GAtPPP *ppp)
void ppp_lcp_down_notify(GAtPPP *ppp)
{
- if (ppp->phase == PPP_PHASE_NETWORK || ppp->phase == PPP_PHASE_LINK_UP)
- pppcp_signal_down(ppp->ipcp);
+ if (ppp->phase == PPP_PHASE_NETWORK ||
+ ppp->phase == PPP_PHASE_LINK_UP) {
+ if (ppp->ipcp)
+ pppcp_signal_down(ppp->ipcp);
+
+ if (ppp->ipv6cp)
+ pppcp_signal_down(ppp->ipv6cp);
+ }
if (ppp->disconnect_reason == G_AT_PPP_REASON_UNKNOWN)
ppp->disconnect_reason = G_AT_PPP_REASON_PEER_CLOSED;
@@ -588,6 +649,11 @@ const char *g_at_ppp_get_password(GAtPPP *ppp)
return ppp->password;
}
+guint8 g_at_ppp_get_proto(GAtPPP *ppp)
+{
+ return ppp->proto;
+}
+
void g_at_ppp_set_recording(GAtPPP *ppp, const char *filename)
{
if (ppp == NULL)
@@ -731,7 +797,12 @@ void g_at_ppp_unref(GAtPPP *ppp)
ppp_chap_free(ppp->chap);
lcp_free(ppp->lcp);
- ipcp_free(ppp->ipcp);
+
+ if (ppp->ipcp)
+ ipcp_free(ppp->ipcp);
+
+ if (ppp->ipv6cp)
+ ipv6cp_free(ppp->ipv6cp);
if (ppp->ppp_dead_source) {
g_source_remove(ppp->ppp_dead_source);
@@ -772,9 +843,11 @@ void g_at_ppp_set_pfc_enabled(GAtPPP *ppp, gboolean enabled)
lcp_set_pfc_enabled(ppp->lcp, enabled);
}
-static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip)
+static GAtPPP *ppp_init_common(guint proto, gboolean is_server, guint32 ip,
+ const char *local_prefix)
{
GAtPPP *ppp;
+ GError *error = NULL;
ppp = g_try_malloc0(sizeof(GAtPPP));
if (ppp == NULL)
@@ -783,6 +856,7 @@ static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip)
ppp->ref_count = 1;
ppp->suspended = TRUE;
ppp->fd = -1;
+ ppp->proto = proto;
/* set options to defaults */
ppp->mru = DEFAULT_MRU;
@@ -791,15 +865,27 @@ static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip)
/* initialize the lcp state */
ppp->lcp = lcp_new(ppp, is_server);
- /* initialize IPCP state */
- ppp->ipcp = ipcp_new(ppp, is_server, ip);
+ if (ppp->proto & G_AT_PPP_PROTO_IP)
+ ppp->ipcp = ipcp_new(ppp, is_server, ip);
+
+ if (ppp->proto & G_AT_PPP_PROTO_IPV6) {
+ ppp->ipv6cp = ipv6cp_new(ppp, FALSE, local_prefix, &error);
+ if (ppp->ipv6cp == NULL) {
+ if (error != NULL) {
+ DBG(ppp, "%s", error->message);
+ g_error_free(error);
+ }
+ g_at_ppp_unref(ppp);
+ return NULL;
+ }
+ }
return ppp;
}
GAtPPP *g_at_ppp_new(void)
{
- return ppp_init_common(FALSE, 0);
+ return ppp_init_common(G_AT_PPP_PROTO_IP, FALSE, 0, NULL);
}
GAtPPP *g_at_ppp_server_new_full(const char *local, int fd)
@@ -812,10 +898,11 @@ GAtPPP *g_at_ppp_server_new_full(const char *local, int fd)
else if (inet_pton(AF_INET, local, &ip) != 1)
return NULL;
- ppp = ppp_init_common(TRUE, ip);
+ ppp = ppp_init_common(G_AT_PPP_PROTO_IP, TRUE, ip, NULL);
+ if (ppp == NULL)
+ return NULL;
- if (ppp != NULL)
- ppp->fd = fd;
+ ppp->fd = fd;
return ppp;
}
@@ -824,3 +911,65 @@ GAtPPP *g_at_ppp_server_new(const char *local)
{
return g_at_ppp_server_new_full(local, -1);
}
+
+GAtPPP *g_at_ppp_ipv6_new(const char *local_prefix)
+{
+ return ppp_init_common(G_AT_PPP_PROTO_IPV6, FALSE, 0, local_prefix);
+}
+
+GAtPPP *g_at_ppp_ipv4v6_new(const char *local_prefix)
+{
+ return ppp_init_common(G_AT_PPP_PROTO_IPV4V6, FALSE, 0, local_prefix);
+}
+
+GAtPPP *g_at_ppp_ipv6_server_new_full(const char *local_prefix, int fd)
+{
+ return ppp_init_common(G_AT_PPP_PROTO_IPV6, TRUE, 0, local_prefix);
+}
+
+GAtPPP *g_at_ppp_ipv6_server_new(const char *local_prefix)
+{
+ return g_at_ppp_ipv6_server_new_full(local_prefix, -1);
+}
+
+GAtPPP *g_at_ppp_ipv4v6_server_new_full(const char *local_ip,
+ const char *local_prefix, int fd)
+{
+ GAtPPP *ppp;
+ guint32 ip;
+
+ if (local_ip == NULL)
+ ip = 0;
+ else if (inet_pton(AF_INET, local_ip, &ip) != 1)
+ return NULL;
+
+ ppp = ppp_init_common(G_AT_PPP_PROTO_IPV4V6, TRUE, ip, local_prefix);
+ if (ppp == NULL)
+ return NULL;
+
+ ppp->fd = fd;
+
+ return ppp;
+}
+
+GAtPPP *g_at_ppp_ipv4v6_server_new(const char *local_ip,
+ const char *local_prefix)
+{
+ return g_at_ppp_ipv4v6_server_new_full(local_ip, local_prefix, -1);
+}
+
+gboolean g_at_ppp_set_ipv6_server_info(GAtPPP *ppp, const char *remote_prefix)
+{
+ GError *error = NULL;
+
+ if (ipv6cp_set_server_info(ppp->ipv6cp, remote_prefix, &error) ==
+ FALSE) {
+ if (error != NULL) {
+ DBG(ppp, "%s", error->message);
+ g_error_free(error);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gatchat/gatppp.h b/gatchat/gatppp.h
index b5a2234..b6eb40d 100644
--- a/gatchat/gatppp.h
+++ b/gatchat/gatppp.h
@@ -31,12 +31,17 @@ extern "C" {
struct _GAtPPP;
+#define G_AT_PPP_PROTO_IP 0x1
+#define G_AT_PPP_PROTO_IPV6 0x2
+#define G_AT_PPP_PROTO_IPV4V6 (G_AT_PPP_PROTO_IP | G_AT_PPP_PROTO_IPV6)
+
typedef struct _GAtPPP GAtPPP;
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 */
@@ -51,8 +56,17 @@ typedef void (*GAtPPPDisconnectFunc)(GAtPPPDisconnectReason reason,
gpointer user_data);
GAtPPP *g_at_ppp_new(void);
+GAtPPP *g_at_ppp_ipv6_new(const char *local_prefix);
+GAtPPP *g_at_ppp_ipv4v6_new(const char *local_prefix);
+
GAtPPP *g_at_ppp_server_new(const char *local);
GAtPPP *g_at_ppp_server_new_full(const char *local, int fd);
+GAtPPP *g_at_ppp_ipv6_server_new(const char *local_prefix);
+GAtPPP *g_at_ppp_ipv6_server_new_full(const char *local_prefix, int fd);
+GAtPPP *g_at_ppp_ipv4v6_server_new(const char *local_ip,
+ const char *local_prefix);
+GAtPPP *g_at_ppp_ipv4v6_server_new_full(const char *local_ip,
+ const char *local_prefix, int fd);
gboolean g_at_ppp_open(GAtPPP *ppp, GAtIO *io);
gboolean g_at_ppp_listen(GAtPPP *ppp, GAtIO *io);
@@ -74,10 +88,13 @@ gboolean g_at_ppp_set_credentials(GAtPPP *ppp, const char *username,
const char *g_at_ppp_get_username(GAtPPP *ppp);
const char *g_at_ppp_get_password(GAtPPP *ppp);
+guint8 g_at_ppp_get_proto(GAtPPP *ppp);
+
void g_at_ppp_set_recording(GAtPPP *ppp, const char *filename);
void g_at_ppp_set_server_info(GAtPPP *ppp, const char *remote_ip,
const char *dns1, const char *dns2);
+gboolean g_at_ppp_set_ipv6_server_info(GAtPPP *ppp, const char *remote_prefix);
void g_at_ppp_set_acfc_enabled(GAtPPP *ppp, gboolean enabled);
void g_at_ppp_set_pfc_enabled(GAtPPP *ppp, gboolean enabled);
diff --git a/gatchat/ppp.h b/gatchat/ppp.h
index 718575b..fa36816 100644
--- a/gatchat/ppp.h
+++ b/gatchat/ppp.h
@@ -99,9 +99,10 @@ void ipcp_set_server_info(struct pppcp_data *ipcp, guint32 peer_addr,
/* IPv6 CP related functions */
struct pppcp_data *ipv6cp_new(GAtPPP *ppp, gboolean is_server,
- const char *local, const char *peer,
- GError **error);
+ const char *local, GError **error);
void ipv6cp_free(struct pppcp_data *data);
+gboolean ipv6cp_set_server_info(struct pppcp_data *pppcp, const char *peer,
+ GError **error);
/* CHAP related functions */
struct ppp_chap *ppp_chap_new(GAtPPP *ppp, guint8 method);
@@ -128,6 +129,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
index ecfd570..4d0926e 100644
--- a/gatchat/ppp_ipv6cp.c
+++ b/gatchat/ppp_ipv6cp.c
@@ -93,9 +93,43 @@ static void ipv6cp_reset_config_options(struct ipv6cp_data *ipv6cp)
ipv6cp_generate_config_options(ipv6cp);
}
+gboolean ipv6cp_set_server_info(struct pppcp_data *pppcp, const char *peer,
+ GError **error)
+{
+ struct ipv6cp_data *ipv6cp = pppcp_get_data(pppcp);
+ struct in6_addr peer_addr;
+
+ if (peer == NULL)
+ memset(&peer_addr, 0, sizeof(peer_addr));
+ else if (inet_pton(AF_INET6, peer, &peer_addr) != 1) {
+ g_set_error(error, IPV6CP_ERROR, errno,
+ "Unable to set peer Interface ID: %s",
+ g_strerror(errno));
+ return FALSE;
+ }
+
+ ipv6cp->is_server = TRUE;
+
+ memcpy(&ipv6cp->peer_addr, &peer_addr.s6_addr[8],
+ sizeof(ipv6cp->peer_addr));
+ return TRUE;
+}
+
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)
@@ -105,11 +139,12 @@ static void ipv6cp_down(struct pppcp_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_server_rcr(struct ipv6cp_data *ipv6cp,
@@ -317,13 +352,11 @@ struct pppcp_proto ipv6cp_proto = {
};
struct pppcp_data *ipv6cp_new(GAtPPP *ppp, gboolean is_server,
- const char *local, const char *peer,
- GError **error)
+ const char *local, GError **error)
{
struct ipv6cp_data *ipv6cp;
struct pppcp_data *pppcp;
struct in6_addr local_addr;
- struct in6_addr peer_addr;
if (local == NULL)
memset(&local_addr, 0, sizeof(local_addr));
@@ -334,15 +367,6 @@ struct pppcp_data *ipv6cp_new(GAtPPP *ppp, gboolean is_server,
return NULL;
}
- if (peer == NULL)
- memset(&peer_addr, 0, sizeof(peer_addr));
- else if (inet_pton(AF_INET6, peer, &peer_addr) != 1) {
- g_set_error(error, IPV6CP_ERROR, errno,
- "Unable to set peer Interface ID: %s",
- g_strerror(errno));
- return NULL;
- }
-
ipv6cp = g_try_new0(struct ipv6cp_data, 1);
if (ipv6cp == NULL)
return NULL;
@@ -355,10 +379,6 @@ struct pppcp_data *ipv6cp_new(GAtPPP *ppp, gboolean is_server,
memcpy(&ipv6cp->local_addr, &local_addr.s6_addr[8],
sizeof(ipv6cp->local_addr));
- memcpy(&ipv6cp->peer_addr, &peer_addr.s6_addr[8],
- sizeof(ipv6cp->peer_addr));
- ipv6cp->is_server = is_server;
-
pppcp_set_data(pppcp, ipv6cp);
ipv6cp_reset_config_options(ipv6cp);
--
1.7.5.4