All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch 1/6] Add PPP protocol support with HDLC framing
       [not found] <20100319194705.214150215@linux.intel.com>
@ 2010-03-19 19:46 ` Kristen Carlson Accardi
  2010-03-20 15:33   ` Marcel Holtmann
  2010-03-19 19:46 ` [patch 2/6] Generic PPP control protocol Kristen Carlson Accardi
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: Kristen Carlson Accardi @ 2010-03-19 19:46 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 23096 bytes --]

This patch implements the basic PPP protocol.  LCP, NCP etc. are handled in a
different patch.

---
 Makefile.am      |    4 
 gatchat/gatppp.c |  133 ++++++++++++++++
 gatchat/gatppp.h |   59 +++++++
 gatchat/ppp.c    |  455 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gatchat/ppp.h    |  130 +++++++++++++++
 5 files changed, 780 insertions(+), 1 deletion(-)

Index: ofono/Makefile.am
===================================================================
--- ofono.orig/Makefile.am	2010-03-19 11:49:00.060469174 -0700
+++ ofono/Makefile.am	2010-03-19 11:49:02.652468489 -0700
@@ -55,7 +55,9 @@
 				gatchat/gattty.h gatchat/gattty.c \
 				gatchat/gatutil.h gatchat/gatutil.c \
 				gatchat/gat.h \
-				gatchat/gatserver.h gatchat/gatserver.c
+				gatchat/gatserver.h gatchat/gatserver.c \
+				gatchat/gatppp.c gatchat/gatppp.h \
+				gatchat/ppp.c gatchat/ppp.h
 
 udev_files = plugins/ofono.rules
 
Index: ofono/gatchat/gatppp.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/gatppp.c	2010-03-19 11:49:02.652468489 -0700
@@ -0,0 +1,133 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+
+#include "gatutil.h"
+#include "gatppp.h"
+#include "ppp.h"
+
+/* Administrative Open */
+void g_at_ppp_open(GAtPPP *ppp)
+{
+	/* send an OPEN event to the lcp layer */
+}
+
+void g_at_ppp_set_connect_function(GAtPPP *ppp,
+			       GAtPPPConnectFunc callback, gpointer user_data)
+{
+	ppp->connect_cb = callback;
+	ppp->connect_data = user_data;
+}
+
+void g_at_ppp_set_disconnect_function(GAtPPP *ppp,
+				  GAtPPPDisconnectFunc callback,
+				  gpointer user_data)
+{
+	ppp->disconnect_cb = callback;
+	ppp->disconnect_data = user_data;
+}
+
+void g_at_ppp_shutdown(GAtPPP *ppp)
+{
+	/* close the ppp */
+	ppp_close(ppp);
+
+	/* clean up all the queues */
+	g_queue_free(ppp->event_queue);
+	g_queue_free(ppp->recv_queue);
+
+	/* cleanup modem channel */
+	g_source_remove(ppp->modem_watch);
+	g_io_channel_unref(ppp->modem);
+}
+
+void g_at_ppp_ref(GAtPPP *ppp)
+{
+	g_atomic_int_inc(&ppp->ref_count);
+}
+
+void g_at_ppp_unref(GAtPPP *ppp)
+{
+	if (g_atomic_int_dec_and_test(&ppp->ref_count)) {
+		g_at_ppp_shutdown(ppp);
+		g_free(ppp);
+	}
+}
+
+GAtPPP *g_at_ppp_new(GIOChannel *modem)
+{
+	GAtPPP *ppp;
+
+	ppp = g_try_malloc0(sizeof(GAtPPP));
+	if (!ppp)
+		return NULL;
+
+	ppp->modem = g_io_channel_ref(modem);
+	if (!g_at_util_setup_io(ppp->modem, G_IO_FLAG_NONBLOCK)) {
+		g_io_channel_unref(modem);
+		g_free(ppp);
+		return NULL;
+	}
+	g_io_channel_set_buffered(modem, FALSE);
+
+	ppp->ref_count = 1;
+
+	/* set options to defaults */
+	ppp->mru = DEFAULT_MRU;
+	ppp->recv_accm = DEFAULT_ACCM;
+	ppp->xmit_accm[0] = DEFAULT_ACCM;
+	ppp->xmit_accm[3] = 0x60000000; /* 0x7d, 0x7e */
+	ppp->pfc = FALSE;
+	ppp->acfc = FALSE;
+
+	/* allocate the queues */
+	ppp->event_queue = g_queue_new();
+	ppp->recv_queue = g_queue_new();
+
+	ppp->index = 0;
+
+	/* initialize the lcp state */
+
+
+	/* initialize the autentication state */
+
+
+	/* intialize the network state */
+
+	/* start listening for packets from the modem */
+	ppp->modem_watch = g_io_add_watch(modem,
+			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+			ppp_cb, ppp);
+
+	return ppp;
+}
Index: ofono/gatchat/gatppp.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/gatppp.h	2010-03-19 11:49:02.652468489 -0700
@@ -0,0 +1,59 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  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
+ *
+ */
+
+#ifndef __G_AT_PPP_H
+#define __G_AT_PPP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _GAtPPP;
+typedef struct _GAtPPP GAtPPP;
+
+typedef enum _GAtPPPConnectStatus {
+	G_AT_PPP_CONNECT_SUCCESS,
+	G_AT_PPP_CONNECT_FAIL
+} GAtPPPConnectStatus;
+
+typedef void (*GAtPPPConnectFunc)(GAtPPP *ppp, GAtPPPConnectStatus success,
+				 guint32 ip_address,
+				 guint32 dns1, guint32 dns2,
+				 gpointer user_data);
+
+typedef void (*GAtPPPDisconnectFunc)(GAtPPP *ppp, gpointer user_data);
+
+GAtPPP * g_at_ppp_new(GIOChannel *modem);
+void g_at_ppp_open(GAtPPP *ppp);
+void g_at_ppp_set_connect_function(GAtPPP *ppp,
+			       GAtPPPConnectFunc callback, gpointer user_data);
+void g_at_ppp_set_disconnect_function(GAtPPP *ppp,
+				  GAtPPPDisconnectFunc callback,
+				  gpointer user_data);
+void g_at_ppp_shutdown(GAtPPP *ppp);
+void g_at_ppp_ref(GAtPPP *ppp);
+void g_at_ppp_unref(GAtPPP *ppp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __G_AT_PPP_H */
+
Index: ofono/gatchat/ppp.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/ppp.c	2010-03-19 11:52:31.011496932 -0700
@@ -0,0 +1,455 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+
+#include "gatutil.h"
+#include "gatppp.h"
+#include "ppp.h"
+
+#define PPPINITFCS16    0xffff  /* Initial FCS value */
+#define PPPGOODFCS16    0xf0b8  /* Good final FCS value */
+
+static GList *packet_handlers = NULL;
+
+void ppp_register_packet_handler(struct ppp_packet_handler *handler)
+{
+	packet_handlers = g_list_append(packet_handlers, handler);
+}
+
+/*
+ * FCS lookup table copied from rfc1662.
+ */
+static guint16 fcstab[256] = {
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/*
+ * Calculate a new fcs given the current fcs and the new data.
+ * copied from rfc1662
+ *
+ *     The FCS field is calculated over all bits of the Address, Control,
+ *     Protocol, Information and Padding fields, not including any start
+ *     and stop bits (asynchronous) nor any bits (synchronous) or octets
+ *     (asynchronous or synchronous) inserted for transparency.  This
+ *     also does not include the Flag Sequences nor the FCS field itself.
+ */
+static guint16 ppp_fcs(guint16 fcs, guint8 c)
+{
+	guint16 new_fcs;
+
+	new_fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
+	return new_fcs;
+}
+
+/*
+ * escape any chars less than 0x20, and check the transmit accm table to
+ * see if this character should be escaped.
+ */
+static gboolean ppp_escape(GAtPPP *ppp, guint8 c, gboolean lcp)
+{
+	if ((lcp && c < 0x20) || (ppp->xmit_accm[c >> 5] & (1 << (c & 0x1f))))
+		return TRUE;
+	return FALSE;
+}
+
+static void ppp_put(GAtPPP *ppp, guint8 *buf, int *pos,
+			guint8 c, gboolean lcp)
+{
+	int i = *pos;
+
+	/* escape characters if needed,  copy into buf, increment pos */
+	if (ppp_escape(ppp, c, lcp)) {
+		buf[i++] = PPP_ESC;
+		buf[i++] = c ^ 0x20;
+	} else
+		buf[i++] = c;
+	*pos = i;
+}
+
+/* XXX implement PFC and ACFC */
+static guint8 *ppp_encode(GAtPPP *ppp, guint8 *data, int len,
+				guint *newlen)
+{
+	int pos = 0;
+	int i = 0;
+	guint16 fcs = PPPINITFCS16;
+	guint16 proto = get_host_short(data);
+	gboolean lcp = (proto == LCP_PROTOCOL);
+	guint8 *frame = g_try_malloc0(BUFFERSZ);
+	if (!frame)
+		return NULL;
+
+	/* copy in the HDLC framing */
+	frame[pos++] = PPP_FLAG_SEQ;
+
+	/* from here till end flag, calculate FCS over each character */
+	fcs = ppp_fcs(fcs, PPP_ADDR_FIELD);
+	ppp_put(ppp, frame, &pos, PPP_ADDR_FIELD, lcp);
+	fcs = ppp_fcs(fcs, PPP_CTRL);
+	ppp_put(ppp, frame, &pos, PPP_CTRL, lcp);
+
+	/*
+	 * for each byte, first calculate FCS, then do escaping if
+	 * neccessary
+	 */
+	while (len--) {
+		fcs = ppp_fcs(fcs, data[i]);
+		ppp_put(ppp, frame, &pos, data[i++], lcp);
+	}
+
+	/* add FCS */
+	fcs ^= 0xffff;                 /* complement */
+	ppp_put(ppp, frame, &pos, (guint8)(fcs & 0x00ff), lcp);
+	ppp_put(ppp, frame, &pos, (guint8)((fcs >> 8) & 0x00ff), lcp);
+
+	/* add flag */
+	frame[pos++] = PPP_FLAG_SEQ;
+
+	*newlen = pos;
+	return frame;
+}
+
+static gint is_proto_handler(gconstpointer a, gconstpointer b)
+{
+	const struct ppp_packet_handler *h = a;
+	const guint16 proto = (guint16) GPOINTER_TO_UINT(b);
+
+	if (h->proto == proto)
+		return 0;
+	else
+		return -1;
+}
+
+/* called when we have received a complete ppp frame */
+static void ppp_recv(GAtPPP *ppp)
+{
+	guint16 protocol;
+	guint8 *frame, *packet;
+	GList *list;
+	struct ppp_packet_handler *h;
+
+	/* pop frames off of receive queue */
+	while ((frame = g_queue_pop_head(ppp->recv_queue))) {
+		protocol = ppp_proto(frame);
+		packet = ppp_info(frame);
+
+		/*
+		 * check to see if we have a protocol handler
+		 * registered for this packet
+		 */
+		list = g_list_find_custom(packet_handlers,
+				GUINT_TO_POINTER(protocol),
+				is_proto_handler);
+		if (list) {
+			h = list->data;
+			h->handler(h->priv, packet);
+		}
+		g_free(frame);
+	}
+}
+
+/* XXX - Implement PFC and ACFC */
+static guint8 *ppp_decode(GAtPPP *ppp, guint8 *frame)
+{
+	guint8 *data;
+	guint pos = 0;
+	int i = 0;
+	int len;
+	guint16 fcs;
+
+	data = g_try_malloc0(ppp->mru + 10);
+	if (!data)
+		return NULL;
+
+	/* skip the first flag char */
+	pos++;
+
+	/* TBD - how to deal with recv_accm */
+	while (frame[pos] != PPP_FLAG_SEQ) {
+		/* scan for escape character */
+		if (frame[pos] == PPP_ESC) {
+			/* skip that char */
+			pos++;
+			data[i] = frame[pos] ^ 0x20;
+		} else
+			data[i] = frame[pos];
+		i++; pos++;
+	}
+
+	len = i;
+
+	/* see if we have a good FCS */
+	fcs = PPPINITFCS16;
+	for (i = 0; i < len; i++)
+		fcs = ppp_fcs(fcs, data[i]);
+
+	if (fcs != PPPGOODFCS16) {
+		g_free(data);
+		return NULL;
+	}
+	return data;
+}
+
+static void ppp_feed(GAtPPP *ppp, guint8 *data, gsize len)
+{
+	guint pos = 0;
+	guint8 *frame;
+
+	/* collect bytes until we detect we have received a complete frame */
+	/* examine the data.  If we are@the beginning of a new frame,
+	 * allocate memory to buffer the frame.
+	 */
+
+	for (pos = 0; pos < len; pos++) {
+		if (data[pos] == PPP_FLAG_SEQ) {
+			if (ppp->index != 0) {
+				/* store last flag character & decode */
+				ppp->buffer[ppp->index++] = data[pos];
+				frame = ppp_decode(ppp, ppp->buffer);
+
+				/* push decoded frame onto receive queue */
+				if (frame)
+					g_queue_push_tail(ppp->recv_queue,
+								frame);
+
+				/* zero buffer */
+				memset(ppp->buffer, 0, BUFFERSZ);
+				ppp->index = 0;
+				continue;
+			}
+		}
+		/* copy byte to buffer */
+		if (ppp->index < BUFFERSZ)
+			ppp->buffer[ppp->index++] = data[pos];
+	}
+	/* process receive queue */
+	ppp_recv(ppp);
+}
+
+/*
+ * transmit out through the lower layer interface
+ *
+ * infolen - length of the information part of the packet
+ */
+void ppp_transmit(GAtPPP *ppp, guint8 *packet, guint infolen)
+{
+	guint8 *frame;
+	guint framelen;
+	GError *error = NULL;
+	GIOStatus status;
+	gsize bytes_written;
+
+	/*
+	 * do the octet stuffing.  Add 2 bytes to the infolen to
+	 * include the protocol field.
+	 */
+	frame = ppp_encode(ppp, packet, infolen + 2, &framelen);
+	if (!frame) {
+		g_printerr("Failed to encode packet to transmit\n");
+		return;
+	}
+
+	/* transmit through the lower layer interface */
+	/*
+	 * TBD - should we just put this on a queue and transmit when
+	 * we won't block, or allow ourselves to block here?
+	 */
+	status = g_io_channel_write_chars(ppp->modem, (gchar *) frame,
+                                          framelen, &bytes_written, &error);
+
+	g_free(frame);
+}
+
+gboolean ppp_cb(GIOChannel *channel, GIOCondition cond, gpointer data)
+{
+	GAtPPP *ppp = data;
+	GIOStatus status;
+	gchar buf[256];
+	gsize bytes_read;
+	GError *error = NULL;
+
+	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+		g_print("G_IO_NVAL | G_IO_ERR");
+		return FALSE;
+	}
+
+	if (cond & G_IO_IN) {
+		status = g_io_channel_read_chars(channel, buf, 256,
+				&bytes_read, &error);
+		if (bytes_read > 0)
+			ppp_feed(ppp, (guint8 *)buf, bytes_read);
+        	if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
+                	return FALSE;
+	}
+
+	return TRUE;
+}
+
+/* Administrative Close */
+void ppp_close(GAtPPP *ppp)
+{
+	/* send a CLOSE event to the lcp layer */
+}
+
+static void ppp_link_establishment(GAtPPP *ppp)
+{
+	/* signal UP event to LCP */
+}
+
+static void ppp_terminate(GAtPPP *ppp)
+{
+	/* signal DOWN event to LCP */
+}
+
+static void ppp_authenticate(GAtPPP *ppp)
+{
+	/* we don't do authentication right now, so send NONE */
+	if (!ppp->auth_proto)
+		ppp_generate_event(ppp, PPP_NONE);
+	/* otherwise we need to wait for the peer to send us a challenge */
+}
+
+static void ppp_dead(GAtPPP *ppp)
+{
+	/* re-initialize everything */
+}
+
+static void ppp_network(GAtPPP *ppp)
+{
+	/* bring network phase up */
+}
+
+static void ppp_transition_phase(GAtPPP *ppp, enum ppp_phase phase)
+{
+	/* don't do anything if we're already there */
+	if (ppp->phase == phase)
+		return;
+
+	/* set new phase */
+	ppp->phase = phase;
+
+	switch (phase) {
+	case PPP_ESTABLISHMENT:
+		ppp_link_establishment(ppp);
+		break;
+	case PPP_AUTHENTICATION:
+		ppp_authenticate(ppp);
+		break;
+	case PPP_TERMINATION:
+		ppp_terminate(ppp);
+		break;
+	case PPP_DEAD:
+		ppp_dead(ppp);
+		break;
+	case PPP_NETWORK:
+		ppp_network(ppp);
+		break;
+	}
+
+}
+
+static void ppp_handle_event(GAtPPP *ppp)
+{
+	enum ppp_event event;
+
+	while ((event = GPOINTER_TO_UINT(g_queue_pop_head(ppp->event_queue)))){
+		switch (event) {
+		case PPP_UP:
+			/* causes transition to ppp establishment */
+			ppp_transition_phase(ppp, PPP_ESTABLISHMENT);
+			break;
+		case PPP_OPENED:
+			ppp_transition_phase(ppp, PPP_AUTHENTICATION);
+			break;
+		case PPP_CLOSING:
+			/* causes transition to termination phase */
+			ppp_transition_phase(ppp, PPP_TERMINATION);
+			break;
+		case PPP_DOWN:
+			/* cases transition to dead phase */
+			ppp_transition_phase(ppp, PPP_DEAD);
+			break;
+		case PPP_NONE:
+		case PPP_SUCCESS:
+			/* causes transition to network phase */
+			ppp_transition_phase(ppp, PPP_NETWORK);
+			break;
+		case PPP_FAIL:
+			if (ppp->phase == PPP_ESTABLISHMENT)
+				ppp_transition_phase(ppp, PPP_DEAD);
+			else if (ppp->phase == PPP_AUTHENTICATION)
+				ppp_transition_phase(ppp, PPP_TERMINATION);
+		}
+	}
+}
+
+/*
+ * send the event handler a new event to process
+ */
+void ppp_generate_event(GAtPPP *ppp, enum ppp_event event)
+{
+	g_queue_push_tail(ppp->event_queue, GUINT_TO_POINTER(event));
+	ppp_handle_event(ppp);
+}
+
Index: ofono/gatchat/ppp.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/ppp.h	2010-03-19 11:51:37.553076071 -0700
@@ -0,0 +1,130 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  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
+ *
+ */
+#define DEFAULT_MRU	1500
+#define BUFFERSZ	DEFAULT_MRU*2
+#define DEFAULT_ACCM	0x00000000
+#define PPP_ESC		0x7d
+#define PPP_FLAG_SEQ 	0x7e
+#define PPP_ADDR_FIELD	0xff
+#define PPP_CTRL	0x03
+#define LCP_PROTOCOL	0xc021
+#define CHAP_PROTOCOL	0xc223
+#define PPP_HEADROOM	2
+#define HDLC_HEADROOM	3
+#define HDLC_TAIL	3
+#define MD5		5
+
+enum ppp_phase {
+	PPP_DEAD = 0,
+	PPP_ESTABLISHMENT,
+	PPP_AUTHENTICATION,
+	PPP_NETWORK,
+	PPP_TERMINATION,
+};
+
+enum ppp_event {
+	PPP_UP = 1,
+	PPP_OPENED,
+	PPP_SUCCESS,
+	PPP_NONE,
+	PPP_CLOSING,
+	PPP_FAIL,
+	PPP_DOWN
+};
+
+struct ppp_packet_handler {
+	guint16 proto;
+	void (*handler)(gpointer priv, guint8 *packet);
+	gpointer priv;
+};
+
+struct ppp_header {
+	guint16 proto;
+	guint8 info[0];
+} __attribute__((packed));
+
+struct packed_short {
+	guint16 s;
+} __attribute__((packed));
+
+struct packed_long {
+	guint32 l;
+} __attribute__((packed));
+
+static inline guint32 __get_unaligned_long(const gpointer p)
+{
+	const struct packed_long *ptr = p;
+	return ptr->l;
+}
+
+static inline guint16 __get_unaligned_short(const gpointer p)
+{
+	const struct packed_short *ptr = p;
+	return ptr->s;
+}
+
+#define get_host_long(p) \
+	(ntohl(__get_unaligned_long(p)))
+
+#define get_host_short(p) \
+	(ntohs(__get_unaligned_short(p)))
+
+#define ppp_info(packet) \
+	(packet + 4)
+
+#define ppp_proto(packet) \
+	(get_host_short(packet + 2))
+
+struct _GAtPPP {
+	gint ref_count;
+	enum ppp_phase phase;
+	guint8 buffer[BUFFERSZ];
+	int index;
+	gint mru;
+	guint16 auth_proto;
+	char user_name[256];
+	char passwd[256];
+	gboolean pfc;
+	gboolean acfc;
+	guint32 xmit_accm[8];
+	guint32 recv_accm;
+	GIOChannel *modem;
+	GQueue *event_queue;
+	GQueue *recv_queue;
+	GAtPPPConnectFunc connect_cb;
+	gpointer connect_data;
+	GAtPPPDisconnectFunc disconnect_cb;
+	gpointer disconnect_data;
+	gint modem_watch;
+};
+
+gboolean ppp_cb(GIOChannel *channel, GIOCondition cond, gpointer data);
+void ppp_close(GAtPPP *ppp);
+void ppp_generate_event(GAtPPP *ppp, enum ppp_event event);
+void ppp_register_packet_handler(struct ppp_packet_handler *handler);
+void ppp_transmit(GAtPPP *ppp, guint8 *packet, guint infolen);
+void ppp_set_auth(GAtPPP *ppp, guint8 *auth_data);
+void ppp_set_recv_accm(GAtPPP *ppp, guint32 accm);
+guint32 ppp_get_xmit_accm(GAtPPP *ppp);
+void ppp_set_pfc(GAtPPP *ppp, gboolean pfc);
+gboolean ppp_get_pfc(GAtPPP *ppp);
+void ppp_set_acfc(GAtPPP *ppp, gboolean acfc);
+gboolean ppp_get_acfc(GAtPPP *ppp);


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [patch 2/6] Generic PPP control protocol
       [not found] <20100319194705.214150215@linux.intel.com>
  2010-03-19 19:46 ` [patch 1/6] Add PPP protocol support with HDLC framing Kristen Carlson Accardi
@ 2010-03-19 19:46 ` Kristen Carlson Accardi
  2010-03-19 19:46 ` [patch 3/6] LCP support Kristen Carlson Accardi
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Kristen Carlson Accardi @ 2010-03-19 19:46 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 45290 bytes --]

Implement a generic control protocol that can be shared by both LCP and NCP
implementations.

---
 Makefile.am      |    3 
 gatchat/ppp.h    |    2 
 gatchat/ppp_cp.c | 1503 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gatchat/ppp_cp.h |  139 +++++
 4 files changed, 1646 insertions(+), 1 deletion(-)

Index: ofono/Makefile.am
===================================================================
--- ofono.orig/Makefile.am	2010-03-19 12:10:04.000000000 -0700
+++ ofono/Makefile.am	2010-03-19 12:28:11.820599845 -0700
@@ -57,7 +57,8 @@
 				gatchat/gat.h \
 				gatchat/gatserver.h gatchat/gatserver.c \
 				gatchat/gatppp.c gatchat/gatppp.h \
-				gatchat/ppp.c gatchat/ppp.h
+				gatchat/ppp.c gatchat/ppp.h gatchat/ppp_cp.h \
+				gatchat/ppp_cp.c
 
 udev_files = plugins/ofono.rules
 
Index: ofono/gatchat/ppp_cp.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/ppp_cp.c	2010-03-19 12:10:09.458490026 -0700
@@ -0,0 +1,1503 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <glib.h>
+#include <arpa/inet.h>
+#include "gatppp.h"
+#include "ppp.h"
+
+#ifdef DEBUG
+const char *pppcp_state_strings[] =
+	{"INITIAL", "STARTING", "CLOSED", "STOPPED", "CLOSING", "STOPPING",
+	"REQSENT", "ACKRCVD", "ACKSENT", "OPENED" };
+
+#define pppcp_trace(p) \
+	(g_print("%s: current state %d:%s\n", __FUNCTION__, \
+		p->state, pppcp_state_strings[p->state]))
+#else
+#define pppcp_trace(p)
+#endif
+
+#define pppcp_to_ppp_packet(p) \
+	(p-PPP_HEADROOM)
+
+struct pppcp_event {
+	enum pppcp_event_type type;
+	gint len;
+	guint8 data[0];
+};
+
+#define INITIAL_RESTART_TIMEOUT	3000
+#define MAX_TERMINATE		2
+#define MAX_CONFIGURE		10
+#define MAX_FAILURE		5
+#define CP_HEADER_SZ		4
+
+static struct pppcp_packet *pppcp_packet_new(struct pppcp_data *data,
+						guint type, guint bufferlen)
+{
+	struct pppcp_packet *packet;
+	struct ppp_header *ppp_packet;
+	guint16 packet_length = bufferlen + sizeof(*packet);
+
+	ppp_packet = g_try_malloc0(packet_length + 2);
+	if (!ppp_packet)
+		return NULL;
+
+	/* add our protocol information */
+	ppp_packet->proto = htons(data->proto);
+
+	/* advance past protocol to add CP header information */
+	packet = (struct pppcp_packet *) (ppp_packet->info);
+
+	packet->length = htons(packet_length);
+	packet->code = type;
+	return packet;
+}
+
+static gboolean pppcp_timeout(gpointer user_data)
+{
+	struct pppcp_data *data = user_data;
+
+	pppcp_trace(data);
+
+	data->restart_timer = 0;
+
+	if (data->restart_counter)
+		pppcp_generate_event(data, TO_PLUS, NULL, 0);
+	else
+		pppcp_generate_event(data, TO_MINUS, NULL, 0);
+	return FALSE;
+}
+
+static void pppcp_start_timer(struct pppcp_data *data)
+{
+	data->restart_timer = g_timeout_add(data->restart_interval,
+				pppcp_timeout, data);
+}
+
+static void pppcp_stop_timer(struct pppcp_data *data)
+{
+	if (data->restart_timer) {
+		g_source_remove(data->restart_timer);
+		data->restart_timer = 0;
+	}
+}
+
+static gboolean pppcp_timer_is_running(struct pppcp_data *data)
+{
+	/* determine if the restart timer is running */
+	if (data->restart_timer)
+		return TRUE;
+	return FALSE;
+}
+
+static struct pppcp_event *pppcp_event_new(enum pppcp_event_type type,
+					gpointer event_data, guint len)
+{
+	struct pppcp_event *event;
+	guint8 *data = event_data;
+
+	event = g_try_malloc0(sizeof(struct pppcp_event) + len);
+	if (!event)
+		return NULL;
+
+	event->type = type;
+	memcpy(event->data, data, len);
+	event->len = len;
+	return event;
+}
+
+static struct pppcp_event *pppcp_get_event(struct pppcp_data *data)
+{
+	return g_queue_pop_head(data->event_queue);
+}
+
+/* actions */
+/* log an illegal event, but otherwise do nothing */
+static void pppcp_illegal_event(guint8 state, guint8 type)
+{
+	g_printerr("Illegal event %d while in state %d\n", type, state);
+}
+
+static void pppcp_this_layer_up(struct pppcp_data *data)
+{
+	struct pppcp_action *action = data->action;
+
+	if (action->this_layer_up)
+		action->this_layer_up(data);
+}
+
+static void pppcp_this_layer_down(struct pppcp_data *data)
+{
+	struct pppcp_action *action = data->action;
+
+	if (action->this_layer_up)
+		action->this_layer_down(data);
+}
+
+static void pppcp_this_layer_started(struct pppcp_data *data)
+{
+	struct pppcp_action *action = data->action;
+
+	if (action->this_layer_up)
+		action->this_layer_started(data);
+}
+
+static void pppcp_this_layer_finished(struct pppcp_data *data)
+{
+	struct pppcp_action *action = data->action;
+
+	if (action->this_layer_up)
+		action->this_layer_finished(data);
+}
+
+static void pppcp_free_option(gpointer data, gpointer user_data)
+{
+	struct ppp_option *option = data;
+	g_free(option);
+}
+
+static void pppcp_clear_options(struct pppcp_data *data)
+{
+	g_list_foreach(data->acceptable_options, pppcp_free_option, NULL);
+	g_list_foreach(data->unacceptable_options, pppcp_free_option, NULL);
+	g_list_foreach(data->rejected_options, pppcp_free_option, NULL);
+	g_list_free(data->acceptable_options);
+	g_list_free(data->unacceptable_options);
+	g_list_free(data->rejected_options);
+	data->acceptable_options = NULL;
+	data->unacceptable_options = NULL;
+	data->rejected_options = NULL;
+}
+
+/*
+ * set the restart counter to either max-terminate
+ * or max-configure.  The counter is decremented for
+ * each transmission, including the first.
+ */
+static void pppcp_initialize_restart_count(struct pppcp_data *data, guint value)
+{
+	pppcp_trace(data);
+	pppcp_clear_options(data);
+	data->restart_counter = value;
+}
+
+/*
+ * set restart counter to zero
+ */
+static void pppcp_zero_restart_count(struct pppcp_data *data)
+{
+	data->restart_counter = 0;
+}
+
+/*
+ * TBD - generate new identifier for packet
+ */
+static guint8 new_identity(struct pppcp_data *data, guint prev_identifier)
+{
+	return prev_identifier+1;
+}
+
+static void get_option_length(gpointer data, gpointer user_data)
+{
+	struct ppp_option *option = data;
+	guint8 *length = user_data;
+
+	*length += option->length;
+}
+
+static void copy_option(gpointer data, gpointer user_data)
+{
+	struct ppp_option *option = data;
+	guint8 **location = user_data;
+	memcpy(*location, (guint8 *) option, option->length);
+	*location += option->length;
+}
+
+void pppcp_add_config_option(struct pppcp_data *data, struct ppp_option *option)
+{
+	data->config_options = g_list_append(data->config_options, option);
+}
+
+/*
+ * transmit a Configure-Request packet
+ * start the restart timer
+ * decrement the restart counter
+ */
+static void pppcp_send_configure_request(struct pppcp_data *data)
+{
+	struct pppcp_packet *packet;
+	guint8 olength = 0;
+	guint8 *odata;
+
+	pppcp_trace(data);
+
+	/* figure out how much space to allocate for options */
+	g_list_foreach(data->config_options, get_option_length, &olength);
+
+	packet = pppcp_packet_new(data, CONFIGURE_REQUEST, olength);
+
+	/* copy config options into packet data */
+	odata = packet->data;
+	g_list_foreach(data->config_options, copy_option, &odata);
+
+	/*
+	 * if this is the first request, we need a new identifier.
+	 * if this is a retransmission, leave the identifier alone.
+	 */
+	if (data->restart_counter == data->max_configure)
+		data->config_identifier =
+			new_identity(data, data->config_identifier);
+	packet->identifier = data->config_identifier;
+
+	ppp_transmit(data->ppp, pppcp_to_ppp_packet((guint8 *) packet),
+			ntohs(packet->length));
+
+	/* XXX don't retransmit right now */
+#if 0
+	data->restart_counter--;
+	pppcp_start_timer(data);
+#endif
+}
+
+/*
+ * transmit a Configure-Ack packet
+ */
+static void pppcp_send_configure_ack(struct pppcp_data *data,
+					guint8 *request)
+{
+	struct pppcp_packet *packet;
+	struct pppcp_packet *pppcp_header = (struct pppcp_packet *) request;
+	guint len;
+	guint8 *odata;
+
+	pppcp_trace(data);
+
+	/* subtract for header. */
+	len = ntohs(pppcp_header->length) - sizeof(*packet);
+
+	packet = pppcp_packet_new(data, CONFIGURE_ACK, len);
+
+	/* copy the applied options in. */
+	odata = packet->data;
+
+	if (g_list_length(data->acceptable_options))
+		g_list_foreach(data->acceptable_options, copy_option, &odata);
+
+	/* match identifier of the request */
+	packet->identifier = pppcp_header->identifier;
+
+	ppp_transmit(data->ppp, pppcp_to_ppp_packet((guint8 *) packet),
+			ntohs(packet->length));
+}
+
+/*
+ * transmit a Configure-Nak or Configure-Reject packet
+ */
+static void pppcp_send_configure_nak(struct pppcp_data *data,
+					guint8 *configure_packet)
+{
+	struct pppcp_packet *packet;
+	struct pppcp_packet *pppcp_header =
+			(struct pppcp_packet *) configure_packet;
+	guint8 olength = 0;
+	guint8 *odata;
+
+	/* if we have any rejected options, send a config-reject */
+	if (g_list_length(data->rejected_options)) {
+		/* figure out how much space to allocate for options */
+		g_list_foreach(data->rejected_options, get_option_length,
+				&olength);
+
+		packet = pppcp_packet_new(data, CONFIGURE_REJECT, olength);
+
+		/* copy the rejected options in. */
+		odata = packet->data;
+		g_list_foreach(data->rejected_options, copy_option,
+				&odata);
+
+		packet->identifier = pppcp_header->identifier;
+		ppp_transmit(data->ppp, pppcp_to_ppp_packet((guint8 *) packet),
+			ntohs(packet->length));
+
+	}
+	/* if we have any unacceptable options, send a config-nak */
+	if (g_list_length(data->unacceptable_options)) {
+		olength = 0;
+
+		/* figure out how much space to allocate for options */
+		g_list_foreach(data->unacceptable_options, get_option_length,
+				&olength);
+
+		packet = pppcp_packet_new(data, CONFIGURE_NAK, olength);
+
+		/* copy the unacceptable options in. */
+		odata = packet->data;
+		g_list_foreach(data->unacceptable_options, copy_option,
+				&odata);
+
+		packet->identifier = pppcp_header->identifier;
+		ppp_transmit(data->ppp, pppcp_to_ppp_packet((guint8 *) packet),
+				ntohs(packet->length));
+	}
+}
+
+/*
+ * transmit a Terminate-Request packet.
+ * start the restart timer.
+ * decrement the restart counter
+ */
+static void pppcp_send_terminate_request(struct pppcp_data *data)
+{
+	struct pppcp_packet *packet;
+
+	/*
+	 * the data field can be used by the sender (us).
+	 * leave this empty for now.
+	 */
+	packet = pppcp_packet_new(data, TERMINATE_REQUEST, 0);
+
+	/*
+	 * Is this a retransmission?  If so, do not change
+	 * the identifier.  If not, we need a fresh identity.
+	 */
+	if (data->restart_counter == data->max_terminate)
+		data->terminate_identifier =
+			new_identity(data, data->terminate_identifier);
+	packet->identifier = data->terminate_identifier;
+	ppp_transmit(data->ppp, pppcp_to_ppp_packet((guint8 *) packet),
+			ntohs(packet->length));
+	data->restart_counter--;
+	pppcp_start_timer(data);
+}
+
+/*
+ * transmit a Terminate-Ack packet
+ */
+static void pppcp_send_terminate_ack(struct pppcp_data *data,
+					guint8 *request)
+{
+	struct pppcp_packet *packet;
+	struct pppcp_packet *pppcp_header = (struct pppcp_packet *) request;
+
+	packet = pppcp_packet_new(data, TERMINATE_ACK, 0);
+
+	/* match identifier of the request */
+	packet->identifier = pppcp_header->identifier;
+
+	ppp_transmit(data->ppp, pppcp_to_ppp_packet((guint8 *) packet),
+			ntohs(pppcp_header->length));
+}
+
+/*
+ * transmit a Code-Reject packet
+ *
+ * XXX this seg faults.
+ */
+static void pppcp_send_code_reject(struct pppcp_data *data,
+					guint8 *rejected_packet)
+{
+	struct pppcp_packet *packet;
+
+	packet = pppcp_packet_new(data, CODE_REJECT,
+			ntohs(((struct pppcp_packet *) rejected_packet)->length));
+
+	/*
+	 * Identifier must be changed for each Code-Reject sent
+	 */
+	packet->identifier = new_identity(data, data->reject_identifier);
+
+	/*
+	 * rejected packet should be copied in, but it should be
+	 * truncated if it needs to be to comply with mtu requirement
+	 */
+	memcpy(packet->data, rejected_packet,
+			ntohs(packet->length - CP_HEADER_SZ));
+
+	ppp_transmit(data->ppp, pppcp_to_ppp_packet((guint8 *) packet),
+			ntohs(packet->length));
+}
+
+/*
+ * transmit an Echo-Reply packet
+ */
+static void pppcp_send_echo_reply(struct pppcp_data *data,
+				guint8 *request)
+{
+	struct pppcp_packet *packet;
+	struct pppcp_packet *header = (struct pppcp_packet *) request;
+
+	/*
+	 * 0 bytes for data, 4 bytes for magic number
+	 */
+	packet = pppcp_packet_new(data, ECHO_REPLY, 4);
+
+	/*
+	 * match identifier of request
+	 */
+	packet->identifier = header->identifier;
+
+	/* magic number? */
+	ppp_transmit(data->ppp, pppcp_to_ppp_packet((guint8 *) packet),
+			ntohs(packet->length));
+
+}
+
+static void pppcp_transition_state(enum pppcp_state new_state,
+					struct pppcp_data *data)
+{
+	/*
+	 * if switching from a state where
+	 * TO events occur, to one where they
+	 * may not, shut off the timer
+	 */
+	switch (new_state) {
+	case INITIAL:
+	case STARTING:
+	case CLOSED:
+	case STOPPED:
+	case OPENED:
+		/* if timer is running, stop it */
+		if (pppcp_timer_is_running(data))
+			pppcp_stop_timer(data);
+		break;
+	case CLOSING:
+	case STOPPING:
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+		break;
+	}
+	data->state = new_state;
+}
+
+static void pppcp_up_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+	switch (data->state) {
+	case INITIAL:
+		/* switch state to CLOSED */
+		pppcp_transition_state(CLOSED, data);
+		break;
+	case STARTING:
+		/* irc, scr/6 */
+		pppcp_initialize_restart_count(data, data->max_configure);
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case CLOSED:
+	case STOPPED:
+	case OPENED:
+	case CLOSING:
+	case STOPPING:
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+		pppcp_illegal_event(data->state, UP);
+	}
+}
+
+static void pppcp_down_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	switch (data->state) {
+	case CLOSED:
+		pppcp_transition_state(INITIAL, data);
+		break;
+	case STOPPED:
+		/* tls/1 */
+		pppcp_transition_state(STARTING, data);
+		pppcp_this_layer_started(data);
+		break;
+	case CLOSING:
+		pppcp_transition_state(INITIAL, data);
+		break;
+	case STOPPING:
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+		pppcp_transition_state(STARTING, data);
+		break;
+	case OPENED:
+		pppcp_transition_state(STARTING, data);
+		pppcp_this_layer_down(data);
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, DOWN);
+		/* illegal */
+	}
+}
+
+static void pppcp_open_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+	switch (data->state) {
+	case INITIAL:
+		/* tls/1 */
+		pppcp_transition_state(STARTING, data);
+		pppcp_this_layer_started(data);
+		break;
+	case STARTING:
+		pppcp_transition_state(STARTING, data);
+		break;
+	case CLOSED:
+		pppcp_initialize_restart_count(data, data->max_configure);
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case STOPPED:
+		/* 3r */
+		pppcp_transition_state(STOPPED, data);
+		break;
+	case CLOSING:
+	case STOPPING:
+		/* 5r */
+		pppcp_transition_state(STOPPING, data);
+		break;
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+		pppcp_transition_state(data->state, data);
+		break;
+	case OPENED:
+		/* 9r */
+		pppcp_transition_state(data->state, data);
+		break;
+	}
+}
+
+static void pppcp_close_event(struct pppcp_data *data, guint8* packet, guint len)
+{
+	switch (data->state) {
+	case INITIAL:
+		pppcp_transition_state(INITIAL, data);
+		break;
+	case STARTING:
+		pppcp_this_layer_finished(data);
+		pppcp_transition_state(INITIAL, data);
+		break;
+	case CLOSED:
+	case STOPPED:
+		pppcp_transition_state(CLOSED, data);
+		break;
+	case CLOSING:
+	case STOPPING:
+		pppcp_transition_state(CLOSING, data);
+		break;
+	case OPENED:
+		pppcp_this_layer_down(data);
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+		pppcp_initialize_restart_count(data, data->max_terminate);
+		pppcp_send_terminate_request(data);
+		pppcp_transition_state(CLOSING, data);
+		break;
+	}
+}
+
+static void pppcp_to_plus_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSING:
+		pppcp_send_terminate_request(data);
+		pppcp_transition_state(CLOSING, data);
+		break;
+	case STOPPING:
+		pppcp_send_terminate_request(data);
+		pppcp_transition_state(STOPPING, data);
+		break;
+	case REQSENT:
+	case ACKRCVD:
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case ACKSENT:
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(ACKSENT, data);
+		break;
+	case INITIAL:
+	case STARTING:
+	case CLOSED:
+	case STOPPED:
+	case OPENED:
+		pppcp_illegal_event(data->state, TO_PLUS);
+	}
+}
+
+static void pppcp_to_minus_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+	switch (data->state) {
+	case CLOSING:
+		pppcp_transition_state(CLOSED, data);
+		pppcp_this_layer_finished(data);
+		break;
+	case STOPPING:
+		pppcp_transition_state(STOPPED, data);
+		pppcp_this_layer_finished(data);
+		break;
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+		/* tlf/3p */
+		pppcp_transition_state(STOPPED, data);
+		pppcp_this_layer_finished(data);
+		break;
+	case INITIAL:
+	case STARTING:
+	case CLOSED:
+	case STOPPED:
+	case OPENED:
+		pppcp_illegal_event(data->state, TO_MINUS);
+	}
+}
+
+static void pppcp_rcr_plus_event(struct pppcp_data *data,
+				guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+	switch (data->state) {
+	case CLOSED:
+		pppcp_send_terminate_ack(data, packet);
+		pppcp_transition_state(CLOSED, data);
+		break;
+	case STOPPED:
+		pppcp_initialize_restart_count(data, data->max_configure);
+		pppcp_send_configure_request(data);
+		pppcp_send_configure_ack(data, packet);
+		pppcp_transition_state(ACKSENT, data);
+		break;
+	case CLOSING:
+	case STOPPING:
+		pppcp_transition_state(data->state, data);
+		break;
+	case REQSENT:
+		pppcp_send_configure_ack(data, packet);
+		pppcp_transition_state(ACKSENT, data);
+		break;
+	case ACKRCVD:
+		pppcp_send_configure_ack(data, packet);
+		pppcp_this_layer_up(data);
+		pppcp_transition_state(OPENED, data);
+		break;
+	case ACKSENT:
+		pppcp_send_configure_ack(data, packet);
+		pppcp_transition_state(ACKSENT, data);
+		break;
+	case OPENED:
+		pppcp_this_layer_down(data);
+		pppcp_send_configure_request(data);
+		pppcp_send_configure_ack(data, packet);
+		pppcp_transition_state(ACKSENT, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RCR_PLUS);
+	}
+}
+
+static void pppcp_rcr_minus_event(struct pppcp_data *data,
+				guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSED:
+		pppcp_send_terminate_ack(data, packet);
+		pppcp_transition_state(CLOSED, data);
+		break;
+	case STOPPED:
+		pppcp_initialize_restart_count(data, data->max_configure);
+		pppcp_send_configure_request(data);
+		pppcp_send_configure_nak(data, packet);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case CLOSING:
+	case STOPPING:
+		pppcp_transition_state(data->state, data);
+		break;
+	case REQSENT:
+	case ACKRCVD:
+		pppcp_send_configure_nak(data, packet);
+		pppcp_transition_state(data->state, data);
+		break;
+	case ACKSENT:
+		pppcp_send_configure_nak(data, packet);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case OPENED:
+		pppcp_this_layer_down(data);
+		pppcp_send_configure_request(data);
+		pppcp_send_configure_nak(data, packet);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RCR_MINUS);
+	}
+}
+
+static void pppcp_rca_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSED:
+	case STOPPED:
+		pppcp_send_terminate_ack(data, packet);
+	case CLOSING:
+	case STOPPING:
+		pppcp_transition_state(data->state, data);
+		break;
+	case REQSENT:
+		pppcp_initialize_restart_count(data, data->max_configure);
+		pppcp_transition_state(ACKRCVD, data);
+		break;
+	case ACKRCVD:
+		/* scr/6x */
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(REQSENT, data);
+	case ACKSENT:
+		pppcp_initialize_restart_count(data, data->max_configure);
+		pppcp_this_layer_up(data);
+		pppcp_transition_state(OPENED, data);
+		break;
+	case OPENED:
+		pppcp_this_layer_down(data);
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RCA);
+	}
+}
+
+static void pppcp_rcn_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSED:
+	case STOPPED:
+		pppcp_send_terminate_ack(data, packet);
+	case CLOSING:
+	case STOPPING:
+		pppcp_transition_state(data->state, data);
+	case REQSENT:
+		pppcp_initialize_restart_count(data, data->max_configure);
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case ACKRCVD:
+		/* scr/6x */
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case ACKSENT:
+		pppcp_initialize_restart_count(data, data->max_configure);
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(ACKSENT, data);
+		break;
+	case OPENED:
+		pppcp_this_layer_down(data);
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RCN);
+	}
+}
+
+static void pppcp_rtr_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSED:
+	case STOPPED:
+		pppcp_send_terminate_ack(data, packet);
+	case CLOSING:
+	case STOPPING:
+		break;
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+		pppcp_send_terminate_ack(data, packet);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case OPENED:
+		pppcp_this_layer_down(data);
+		pppcp_zero_restart_count(data);
+		pppcp_send_terminate_ack(data, packet);
+		pppcp_transition_state(STOPPING, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RTR);
+	}
+}
+
+static void pppcp_rta_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSED:
+	case STOPPED:
+		pppcp_transition_state(data->state, data);
+		break;
+	case CLOSING:
+		pppcp_this_layer_finished(data);
+		pppcp_transition_state(CLOSED, data);
+		break;
+	case STOPPING:
+		pppcp_this_layer_finished(data);
+		pppcp_transition_state(STOPPED, data);
+		break;
+	case REQSENT:
+	case ACKRCVD:
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case ACKSENT:
+		pppcp_transition_state(ACKSENT, data);
+		break;
+	case OPENED:
+		pppcp_this_layer_down(data);
+		pppcp_send_configure_request(data);
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RTA);
+	}
+}
+
+static void pppcp_ruc_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSED:
+	case STOPPED:
+	case CLOSING:
+	case STOPPING:
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+	case OPENED:
+		pppcp_send_code_reject(data, packet);
+		pppcp_transition_state(data->state, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RUC);
+	}
+}
+
+static void pppcp_rxj_plus_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSED:
+	case STOPPED:
+	case CLOSING:
+	case STOPPING:
+		pppcp_transition_state(data->state, data);
+		break;
+	case REQSENT:
+	case ACKRCVD:
+		pppcp_transition_state(REQSENT, data);
+		break;
+	case ACKSENT:
+	case OPENED:
+		pppcp_transition_state(data->state, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RXJ_PLUS);
+	}
+}
+
+static void pppcp_rxj_minus_event(struct pppcp_data *data,
+				guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSED:
+	case STOPPED:
+		pppcp_this_layer_finished(data);
+		pppcp_transition_state(data->state, data);
+		break;
+	case CLOSING:
+		pppcp_this_layer_finished(data);
+		pppcp_transition_state(CLOSED, data);
+		break;
+	case STOPPING:
+		pppcp_this_layer_finished(data);
+		pppcp_transition_state(STOPPED, data);
+		break;
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+		pppcp_this_layer_finished(data);
+		pppcp_transition_state(STOPPED, data);
+		break;
+	case OPENED:
+		pppcp_this_layer_down(data);
+		pppcp_initialize_restart_count(data, data->max_terminate);
+		pppcp_send_terminate_request(data);
+		pppcp_transition_state(STOPPING, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RXJ_MINUS);
+	}
+}
+
+static void pppcp_rxr_event(struct pppcp_data *data, guint8 *packet, guint len)
+{
+	pppcp_trace(data);
+
+	switch (data->state) {
+	case CLOSED:
+	case STOPPED:
+	case CLOSING:
+	case STOPPING:
+	case REQSENT:
+	case ACKRCVD:
+	case ACKSENT:
+		pppcp_transition_state(data->state, data);
+		break;
+	case OPENED:
+		pppcp_send_echo_reply(data, packet);
+		pppcp_transition_state(OPENED, data);
+		break;
+	case INITIAL:
+	case STARTING:
+		pppcp_illegal_event(data->state, RXR);
+	}
+}
+
+static void pppcp_handle_event(gpointer user_data)
+{
+	struct pppcp_event *event;
+	struct pppcp_data *data = user_data;
+
+	while ((event = pppcp_get_event(data))) {
+		if (event->type > RXR)
+			pppcp_illegal_event(data->state, event->type);
+		else
+			data->event_ops[event->type](data, event->data,
+							event->len);
+		g_free(event);
+	}
+}
+
+/*
+ * send the event handler a new event to process
+ */
+void pppcp_generate_event(struct pppcp_data *data,
+				enum pppcp_event_type event_type,
+				gpointer event_data, guint data_len)
+{
+	struct pppcp_event *event;
+
+	event = pppcp_event_new(event_type, event_data, data_len);
+	if (event)
+		g_queue_push_tail(data->event_queue, event);
+	pppcp_handle_event(data);
+}
+
+static gint is_option(gconstpointer a, gconstpointer b)
+{
+	const struct ppp_option *o = a;
+	guint8 otype = (guint8) GPOINTER_TO_UINT(b);
+
+	if (o->type == otype)
+		return 0;
+	else
+		return -1;
+}
+
+static void verify_config_option(gpointer elem, gpointer user_data)
+{
+	struct ppp_option *config = elem;
+	struct pppcp_data *data = user_data;
+	GList *list = NULL;
+	struct ppp_option *option;
+
+	/*
+	 * determine whether this config option is in the
+	 * acceptable options list
+	 */
+	if (g_list_length(data->acceptable_options))
+		list = g_list_find_custom(data->acceptable_options,
+				GUINT_TO_POINTER(config->type),
+				is_option);
+	if (!list) {
+		/*
+		 * if the option did not exist, we need to store a copy
+		 * of the option in the unacceptable_options list so it
+		 * can be nak'ed.
+		 */
+		option = g_try_malloc0(config->length);
+		if (option == NULL)
+			return;
+		option->type = config->type;
+		option->length = config->length;
+		data->unacceptable_options =
+			g_list_append(data->unacceptable_options, option);
+	}
+
+}
+
+static void remove_config_option(gpointer elem, gpointer user_data)
+{
+	struct ppp_option *config = elem;
+	struct pppcp_data *data = user_data;
+	GList *list;
+
+	/*
+	 * determine whether this config option is in the
+	 * applied options list
+	 */
+	if (g_list_length(data->config_options)) {
+		list = g_list_find_custom(data->config_options,
+				GUINT_TO_POINTER(config->type),
+				is_option);
+		if (list)
+			data->config_options =
+				g_list_delete_link(data->config_options, list);
+	}
+}
+
+static guint8 pppcp_process_configure_request(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	gint len;
+	int i = 0;
+	struct ppp_option *option;
+	enum option_rval rval = OPTION_ERR;
+	struct pppcp_action *action = data->action;
+
+	pppcp_trace(data);
+
+	len = ntohs(packet->length) - CP_HEADER_SZ;
+
+	/*
+	 * check the options.
+	 */
+	while (i < len) {
+		guint8 otype = packet->data[i];
+		guint8 olen = packet->data[i+1];
+		option = g_try_malloc0(olen);
+		if (option == NULL)
+			break;
+		option->type = otype;
+		option->length = olen;
+		memcpy(option->data, &packet->data[i+2], olen-2);
+		if (action->option_scan)
+			rval = action->option_scan(option, data);
+		switch (rval) {
+		case OPTION_ACCEPT:
+			data->acceptable_options =
+				g_list_append(data->acceptable_options, option);
+			break;
+		case OPTION_REJECT:
+			data->rejected_options =
+				g_list_append(data->rejected_options, option);
+			break;
+		case OPTION_NAK:
+			data->unacceptable_options =
+				g_list_append(data->unacceptable_options,
+						option);
+			break;
+		case OPTION_ERR:
+			g_printerr("unhandled option type %d\n", otype);
+		}
+		/* skip ahead to the next option */
+		i += olen;
+	}
+
+	/* make sure all required config options were included */
+	g_list_foreach(data->config_options, verify_config_option, data);
+
+	if (g_list_length(data->unacceptable_options) ||
+			g_list_length(data->rejected_options))
+		return RCR_MINUS;
+
+	/*
+	 * all options were acceptable, so we should apply them before
+	 * sending a configure-ack
+	 *
+	 * Remove all applied options from the config_option list.  The
+	 * protocol will have to re-add them if they want them renegotiated
+	 * when the ppp goes down.
+	 */
+	if (action->option_process) {
+		g_list_foreach(data->acceptable_options,
+				action->option_process, data->priv);
+		g_list_foreach(data->acceptable_options, remove_config_option,
+				data);
+	}
+
+	return RCR_PLUS;
+}
+
+static guint8 pppcp_process_configure_ack(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	guint len;
+	GList *list;
+	struct ppp_option *acked_option;
+	guint i = 0;
+	struct pppcp_action *action = data->action;
+
+	pppcp_trace(data);
+
+	len = ntohs(packet->length) - CP_HEADER_SZ;
+
+	/* if identifiers don't match, we should silently discard */
+	if (packet->identifier != data->config_identifier) {
+		g_printerr("received an ack id %d, but config id is %d\n",
+			packet->identifier, data->config_identifier);
+		return 0;
+	}
+
+	/*
+	 * check each acked option.  If it is what we requested,
+	 * then we can apply these option values.
+	 *
+	 * XXX what if it isn't?  Do this correctly -- for now
+	 * we are just going to assume that all options matched
+	 * and apply them.
+	 */
+	while (i < len) {
+		guint8 otype = packet->data[i];
+		guint8 olen = packet->data[i + 1];
+		acked_option = g_try_malloc0(olen);
+		if (acked_option == NULL)
+			break;
+		acked_option->type = otype;
+		acked_option->length = olen;
+		memcpy(acked_option->data, &packet->data[i + 2], olen - 2);
+		list = g_list_find_custom(data->config_options,
+				GUINT_TO_POINTER(acked_option->type),
+				is_option);
+		if (list) {
+			/*
+			 * once we've applied the option, delete it from
+		 	 * the config_options list.
+			 */
+			if (action->option_process)
+				action->option_process(acked_option,
+							data->priv);
+			data->config_options =
+				g_list_delete_link(data->config_options, list);
+		} else
+			g_printerr("oops -- found acked option %d we didn't request\n", acked_option->type);
+		g_free(acked_option);
+
+		/* skip ahead to the next option */
+		i += olen;
+	}
+	return RCA;
+}
+
+static guint8 pppcp_process_configure_nak(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	guint len;
+	GList *list;
+	struct ppp_option *naked_option;
+	struct ppp_option *config_option;
+	guint i = 0;
+	enum option_rval rval = OPTION_ERR;
+	struct pppcp_action *action = data->action;
+
+	pppcp_trace(data);
+
+	len = ntohs(packet->length) - CP_HEADER_SZ;
+
+	/* if identifiers don't match, we should silently discard */
+	if (packet->identifier != data->config_identifier)
+		return 0;
+
+	/*
+	 * check each unacceptable option.  If it is acceptable, then
+	 * we can resend the configure request with this value. we need
+	 * to check the current config options to see if we need to
+	 * modify a value there, or add a new option.
+	 */
+	while (i < len) {
+		guint8 otype = packet->data[i];
+		guint8 olen = packet->data[i+1];
+		naked_option = g_try_malloc0(olen);
+		if (naked_option == NULL)
+			break;
+		naked_option->type = otype;
+		naked_option->length = olen;
+		memcpy(naked_option->data, &packet->data[i + 2], olen - 2);
+		if (action->option_scan)
+			rval = action->option_scan(naked_option, data);
+		if (rval == OPTION_ACCEPT) {
+			/*
+			 * check the current config options to see if they
+			 * match.
+			 */
+			list = g_list_find_custom(data->config_options,
+				GUINT_TO_POINTER(otype),
+				is_option);
+			if (list) {
+				/* modify current option value to match */
+				config_option = list->data;
+
+				/*
+				 * option values should match, otherwise
+				 * we need to reallocate
+				 */
+				if ((config_option->length ==
+					naked_option->length) && (olen - 2)) {
+						memcpy(config_option->data,
+							naked_option->data,
+							olen - 2);
+				} else {
+					/* XXX implement this */
+					g_printerr("uh oh, option value doesn't match\n");
+				}
+				g_free(naked_option);
+			} else {
+				/* add to list of config options */
+				pppcp_add_config_option(data, naked_option);
+			}
+		} else {
+			/* XXX handle this correctly */
+			g_printerr("oops, option wasn't acceptable\n");
+			g_free(naked_option);
+		}
+
+		/* skip ahead to the next option */
+		i += olen;
+	}
+	return RCN;
+}
+
+static guint8 pppcp_process_configure_reject(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	/*
+	 * make sure identifier matches that of last sent configure
+	 * request
+	 */
+	if (packet->identifier == data->config_identifier) {
+		/*
+		 * check to see which options were rejected
+		 * Rejected options must be a subset of requested
+		 * options.
+		 *
+		 * when a new configure-request is sent, we may
+		 * not request any of these options be negotiated
+		 */
+		return RCN;
+	}
+	return 0;
+}
+
+static guint8 pppcp_process_terminate_request(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	return RTR;
+}
+
+static guint8 pppcp_process_terminate_ack(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	/*
+	 * if we wind up using the data field for anything, then
+	 * we'd want to check the identifier.
+	 * even if the identifiers don't match, we still handle
+	 * a terminate ack, as it is allowed to be unelicited
+	 */
+	return RTA;
+}
+
+static guint8 pppcp_process_code_reject(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	/*
+	 * determine if the code reject is catastrophic or not.
+	 * return RXJ_PLUS if this reject is acceptable, RXJ_MINUS if
+	 * it is catastrophic.
+	 */
+	return RXJ_MINUS;
+}
+
+static guint8 pppcp_process_protocol_reject(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	/*
+	 * determine if the protocol reject is catastrophic or not.
+	 * return RXJ_PLUS if this reject is acceptable, RXJ_MINUS if
+	 * it is catastrophic.
+	 */
+	return RXJ_MINUS;
+}
+
+static guint8 pppcp_process_echo_request(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	return RXR;
+}
+
+static guint8 pppcp_process_echo_reply(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	return 0;
+}
+
+static guint8 pppcp_process_discard_request(struct pppcp_data *data,
+					struct pppcp_packet *packet)
+{
+	return 0;
+}
+
+/*
+ * parse the packet and determine which event this packet caused
+ */
+void pppcp_process_packet(gpointer priv, guint8 *new_packet)
+{
+	struct pppcp_data *data = priv;
+	struct pppcp_packet *packet = (struct pppcp_packet *) new_packet;
+	guint8 event_type;
+	gpointer event_data = NULL;
+	guint data_len = 0;
+
+	if (data == NULL)
+		return;
+
+	/* check flags to see if we support this code */
+	if (!(data->valid_codes & (1 << packet->code))) {
+		event_type = RUC;
+	} else
+		event_type = data->packet_ops[packet->code-1](data, packet);
+	if (event_type) {
+		data_len = ntohs(packet->length);
+		event_data = packet;
+		pppcp_generate_event(data, event_type, event_data, data_len);
+	}
+}
+
+void pppcp_set_valid_codes(struct pppcp_data *data, guint16 codes)
+{
+	if (data == NULL)
+		return;
+
+	data->valid_codes = codes;
+}
+
+void pppcp_free(struct pppcp_data *data)
+{
+	if (data == NULL)
+		return;
+
+	/* free event queue */
+	if (!g_queue_is_empty(data->event_queue))
+		g_queue_foreach(data->event_queue, (GFunc) g_free, NULL);
+	g_queue_free(data->event_queue);
+
+	/* remove all config options */
+	pppcp_clear_options(data);
+
+	/* free self */
+	g_free(data);
+}
+
+struct pppcp_data *pppcp_new(GAtPPP *ppp, guint16 proto,
+				gpointer priv)
+{
+	struct pppcp_data *data;
+
+	data = g_try_malloc0(sizeof(struct pppcp_data));
+	if (!data)
+		return NULL;
+
+	data->state = INITIAL;
+	data->restart_interval = INITIAL_RESTART_TIMEOUT;
+	data->max_terminate = MAX_TERMINATE;
+	data->max_configure = MAX_CONFIGURE;
+	data->max_failure = MAX_FAILURE;
+	data->event_queue = g_queue_new();
+	data->identifier = 0;
+	data->ppp = ppp;
+	data->proto = proto;
+	data->priv = priv;
+
+	/* setup func ptrs for processing packet by pppcp code */
+	data->packet_ops[CONFIGURE_REQUEST - 1] =
+					pppcp_process_configure_request;
+	data->packet_ops[CONFIGURE_ACK - 1] = pppcp_process_configure_ack;
+	data->packet_ops[CONFIGURE_NAK - 1] = pppcp_process_configure_nak;
+	data->packet_ops[CONFIGURE_REJECT - 1] = pppcp_process_configure_reject;
+	data->packet_ops[TERMINATE_REQUEST - 1] =
+					pppcp_process_terminate_request;
+	data->packet_ops[TERMINATE_ACK - 1] = pppcp_process_terminate_ack;
+	data->packet_ops[CODE_REJECT - 1] = pppcp_process_code_reject;
+	data->packet_ops[PROTOCOL_REJECT - 1] = pppcp_process_protocol_reject;
+	data->packet_ops[ECHO_REQUEST - 1] = pppcp_process_echo_request;
+	data->packet_ops[ECHO_REPLY - 1] = pppcp_process_echo_reply;
+	data->packet_ops[DISCARD_REQUEST - 1] = pppcp_process_discard_request;
+
+	/* setup func ptrs for handling events by event type */
+	data->event_ops[UP] = pppcp_up_event;
+	data->event_ops[DOWN] = pppcp_down_event;
+	data->event_ops[OPEN] = pppcp_open_event;
+	data->event_ops[CLOSE] = pppcp_close_event;
+	data->event_ops[TO_PLUS] = pppcp_to_plus_event;
+	data->event_ops[TO_MINUS] = pppcp_to_minus_event;
+	data->event_ops[RCR_PLUS] = pppcp_rcr_plus_event;
+	data->event_ops[RCR_MINUS] = pppcp_rcr_minus_event;
+	data->event_ops[RCA] = pppcp_rca_event;
+	data->event_ops[RCN] = pppcp_rcn_event;
+	data->event_ops[RTR] = pppcp_rtr_event;
+	data->event_ops[RTA] = pppcp_rta_event;
+	data->event_ops[RUC] = pppcp_ruc_event;
+	data->event_ops[RXJ_PLUS] = pppcp_rxj_plus_event;
+	data->event_ops[RXJ_MINUS] = pppcp_rxj_minus_event;
+	data->event_ops[RXR] = pppcp_rxr_event;
+
+	return data;
+}
Index: ofono/gatchat/ppp_cp.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/ppp_cp.h	2010-03-19 12:10:09.459488338 -0700
@@ -0,0 +1,139 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  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
+ *
+ */
+
+struct pppcp_data;
+
+enum pppcp_code {
+	CONFIGURE_REQUEST = 1,
+	CONFIGURE_ACK,
+	CONFIGURE_NAK,
+	CONFIGURE_REJECT,
+	TERMINATE_REQUEST,
+	TERMINATE_ACK,
+	CODE_REJECT,
+	PROTOCOL_REJECT,
+	ECHO_REQUEST,
+	ECHO_REPLY,
+	DISCARD_REQUEST
+};
+
+enum pppcp_event_type {
+	UP,
+	DOWN,
+	OPEN,
+	CLOSE,
+	TO_PLUS,
+	TO_MINUS,
+	RCR_PLUS,
+	RCR_MINUS,
+	RCA,
+	RCN,
+	RTR,
+	RTA,
+	RUC,
+	RXJ_PLUS,
+	RXJ_MINUS,
+	RXR,
+};
+
+enum pppcp_state {
+	INITIAL,
+	STARTING,
+	CLOSED,
+	STOPPED,
+	CLOSING,
+	STOPPING,
+	REQSENT,
+	ACKRCVD,
+	ACKSENT,
+	OPENED,
+};
+
+/* option format */
+struct ppp_option {
+	guint8 type;
+	guint8 length;
+	guint8 data[0];
+};
+
+enum option_rval {
+	OPTION_ACCEPT,
+	OPTION_REJECT,
+	OPTION_NAK,
+	OPTION_ERR,
+};
+
+struct pppcp_action {
+	void (*this_layer_up)(struct pppcp_data *data);
+	void (*this_layer_down)(struct pppcp_data *data);
+	void (*this_layer_started)(struct pppcp_data *data);
+	void (*this_layer_finished)(struct pppcp_data *data);
+	enum option_rval (*option_scan)(struct ppp_option *option,
+						gpointer user_data);
+	void (*option_process)(gpointer option, gpointer user_data);
+};
+
+struct pppcp_packet {
+	guint8 code;
+	guint8 identifier;
+	guint16 length;
+	guint8 data[0];
+} __attribute__((packed));
+
+struct pppcp_data {
+	enum pppcp_state state;
+	guint restart_timer;
+	guint restart_counter;
+	guint restart_interval;
+	guint max_terminate;
+	guint max_configure;
+	guint max_failure;
+	guint32 magic_number;
+	GQueue *event_queue;
+	GList *config_options;
+	GList *acceptable_options;
+	GList *unacceptable_options;
+	GList *rejected_options;
+	GList *applied_options;
+	GAtPPP *ppp;
+	guint8 identifier;  /* don't think I need this now */
+	guint8 config_identifier;
+	guint8 terminate_identifier;
+	guint8 reject_identifier;
+	struct pppcp_action *action;
+	guint16 valid_codes;
+	guint8 (*packet_ops[11])(struct pppcp_data *data,
+					struct pppcp_packet *packet);
+	void (*event_ops[16])(struct pppcp_data *data, guint8 *packet,
+				guint length);
+	gpointer priv;
+	guint16 proto;
+};
+
+struct pppcp_data *pppcp_new(GAtPPP *ppp, guint16 proto, gpointer priv);
+void pppcp_free(struct pppcp_data *data);
+void pppcp_add_config_option(struct pppcp_data *data,
+				struct ppp_option *option);
+void pppcp_set_valid_codes(struct pppcp_data *data, guint16 codes);
+void pppcp_generate_event(struct pppcp_data *data,
+				enum pppcp_event_type event_type,
+				gpointer event_data, guint data_len);
+void pppcp_process_packet(gpointer priv, guint8 *new_packet);
Index: ofono/gatchat/ppp.h
===================================================================
--- ofono.orig/gatchat/ppp.h	2010-03-19 12:10:04.000000000 -0700
+++ ofono/gatchat/ppp.h	2010-03-19 12:28:11.820599845 -0700
@@ -18,6 +18,8 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+#include "ppp_cp.h"
+
 #define DEFAULT_MRU	1500
 #define BUFFERSZ	DEFAULT_MRU*2
 #define DEFAULT_ACCM	0x00000000


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [patch 3/6] LCP support
       [not found] <20100319194705.214150215@linux.intel.com>
  2010-03-19 19:46 ` [patch 1/6] Add PPP protocol support with HDLC framing Kristen Carlson Accardi
  2010-03-19 19:46 ` [patch 2/6] Generic PPP control protocol Kristen Carlson Accardi
@ 2010-03-19 19:46 ` Kristen Carlson Accardi
  2010-03-19 19:46 ` [patch 4/6] CHAP with MD5 authentication Kristen Carlson Accardi
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Kristen Carlson Accardi @ 2010-03-19 19:46 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 9916 bytes --]

Implement LCP support for the PPP protocol

---
 Makefile.am       |    2 
 gatchat/gatppp.c  |    6 +
 gatchat/ppp.c     |   48 ++++++++++
 gatchat/ppp.h     |    8 +
 gatchat/ppp_lcp.c |  246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 308 insertions(+), 2 deletions(-)

Index: ofono/Makefile.am
===================================================================
--- ofono.orig/Makefile.am	2010-03-19 12:29:00.582475429 -0700
+++ ofono/Makefile.am	2010-03-19 12:29:53.977602617 -0700
@@ -58,7 +58,7 @@
 				gatchat/gatserver.h gatchat/gatserver.c \
 				gatchat/gatppp.c gatchat/gatppp.h \
 				gatchat/ppp.c gatchat/ppp.h gatchat/ppp_cp.h \
-				gatchat/ppp_cp.c
+				gatchat/ppp_cp.c gatchat/ppp_lcp.c
 
 udev_files = plugins/ofono.rules
 
Index: ofono/gatchat/ppp.c
===================================================================
--- ofono.orig/gatchat/ppp.c	2010-03-19 12:28:11.820599845 -0700
+++ ofono/gatchat/ppp.c	2010-03-19 12:29:53.978616154 -0700
@@ -350,16 +350,19 @@
 void ppp_close(GAtPPP *ppp)
 {
 	/* send a CLOSE event to the lcp layer */
+	lcp_close(ppp->lcp);
 }
 
 static void ppp_link_establishment(GAtPPP *ppp)
 {
 	/* signal UP event to LCP */
+	lcp_establish(ppp->lcp);
 }
 
 static void ppp_terminate(GAtPPP *ppp)
 {
 	/* signal DOWN event to LCP */
+	lcp_terminate(ppp->lcp);
 }
 
 static void ppp_authenticate(GAtPPP *ppp)
@@ -453,3 +456,48 @@
 	ppp_handle_event(ppp);
 }
 
+void ppp_set_auth(GAtPPP *ppp, guint8* auth_data)
+{
+	guint16 proto = get_host_short(auth_data);
+
+	switch (proto) {
+	case CHAP_PROTOCOL:
+		/* get the algorithm */
+		break;
+	default:
+		g_printerr("unknown authentication proto\n");
+		break;
+	}
+}
+
+void ppp_set_recv_accm(GAtPPP *ppp, guint32 accm)
+{
+	ppp->recv_accm = accm;
+}
+
+guint32 ppp_get_xmit_accm(GAtPPP *ppp)
+{
+	return ppp->xmit_accm[0];
+}
+
+void ppp_set_pfc(GAtPPP *ppp, gboolean pfc)
+{
+	ppp->pfc = pfc;
+}
+
+gboolean ppp_get_pfc(GAtPPP *ppp)
+{
+	return ppp->pfc;
+}
+
+void ppp_set_acfc(GAtPPP *ppp, gboolean acfc)
+{
+	ppp->acfc = acfc;
+}
+
+gboolean ppp_get_acfc(GAtPPP *ppp)
+{
+	return ppp->acfc;
+}
+
+
Index: ofono/gatchat/ppp.h
===================================================================
--- ofono.orig/gatchat/ppp.h	2010-03-19 12:29:00.584486998 -0700
+++ ofono/gatchat/ppp.h	2010-03-19 12:29:53.979593793 -0700
@@ -98,6 +98,7 @@
 struct _GAtPPP {
 	gint ref_count;
 	enum ppp_phase phase;
+	struct pppcp_data *lcp;
 	guint8 buffer[BUFFERSZ];
 	int index;
 	gint mru;
@@ -130,3 +131,10 @@
 gboolean ppp_get_pfc(GAtPPP *ppp);
 void ppp_set_acfc(GAtPPP *ppp, gboolean acfc);
 gboolean ppp_get_acfc(GAtPPP *ppp);
+struct pppcp_data * lcp_new(GAtPPP *ppp);
+void lcp_free(struct pppcp_data *lcp);
+void lcp_open(struct pppcp_data *data);
+void lcp_close(struct pppcp_data *data);
+void lcp_establish(struct pppcp_data *data);
+void lcp_terminate(struct pppcp_data *data);
+
Index: ofono/gatchat/ppp_lcp.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/ppp_lcp.c	2010-03-19 12:29:53.979593793 -0700
@@ -0,0 +1,246 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <glib.h>
+#include <arpa/inet.h>
+#include "gatppp.h"
+#include "ppp.h"
+
+enum lcp_options {
+	RESERVED 	= 0,
+	MRU		= 1,
+	ACCM		= 2,
+	AUTH_PROTO	= 3,
+	QUAL_PROTO	= 4,
+	MAGIC_NUMBER	= 5,
+	DEPRECATED_QUAL_PROTO	= 6,
+	PFC			= 7,
+	ACFC			= 8,
+};
+
+#define LCP_SUPPORTED_CODES	((1 << CONFIGURE_REQUEST) | \
+				(1 << CONFIGURE_ACK) | \
+				(1 << CONFIGURE_NAK) | \
+				(1 << CONFIGURE_REJECT) | \
+				(1 << TERMINATE_REQUEST) | \
+				(1 << TERMINATE_ACK) | \
+				(1 << CODE_REJECT) | \
+				(1 << PROTOCOL_REJECT) | \
+				(1 << ECHO_REQUEST) | \
+				(1 << ECHO_REPLY) | \
+				(1 << DISCARD_REQUEST))
+
+/*
+ * signal the Up event to the NCP
+ */
+static void lcp_up(struct pppcp_data *pppcp)
+{
+	ppp_generate_event(pppcp->ppp, PPP_OPENED);
+}
+
+/*
+ * signal the Down event to the NCP
+ */
+static void lcp_down(struct pppcp_data *pppcp)
+{
+	ppp_generate_event(pppcp->ppp, PPP_DOWN);
+}
+
+/*
+ * Indicate that the lower layer is now needed
+ * Should trigger Up event
+ */
+static void lcp_started(struct pppcp_data *pppcp)
+{
+	ppp_generate_event(pppcp->ppp, PPP_UP);
+}
+
+/*
+ * Indicate that the lower layer is not needed
+ * Should trigger Down event
+ */
+static void lcp_finished(struct pppcp_data *pppcp)
+{
+	ppp_generate_event(pppcp->ppp, PPP_CLOSING);
+}
+
+/*
+ * Scan the option to see if it is acceptable, unacceptable, or rejected
+ *
+ * We need to use a default case here because this option type value
+ * could be anything.
+ */
+static guint lcp_option_scan(struct ppp_option *option, gpointer user)
+{
+	switch (option->type) {
+	case ACCM:
+	case AUTH_PROTO:
+		/* XXX check to make sure it's a proto we recognize */
+	case MAGIC_NUMBER:
+	case PFC:
+	case ACFC:
+		return OPTION_ACCEPT;
+		break;
+	default:
+		return OPTION_REJECT;
+	}
+}
+
+/*
+ * act on an acceptable option
+ *
+ * We need to use a default case here because this option type value
+ * could be anything.
+ */
+static void lcp_option_process(gpointer data, gpointer user)
+{
+	struct ppp_option *option = data;
+	struct pppcp_data *pppcp = user;
+	GAtPPP *ppp = pppcp->ppp;
+	guint32 magic;
+
+	switch (option->type) {
+	case ACCM:
+		ppp_set_recv_accm(ppp, get_host_long(option->data));
+		break;
+	case AUTH_PROTO:
+		ppp_set_auth(ppp, option->data);
+		break;
+	case MAGIC_NUMBER:
+		/* XXX handle loopback */
+		magic = get_host_long(option->data);
+		if (magic != pppcp->magic_number)
+			pppcp->magic_number = magic;
+		else
+			g_print("looped back? I should do something\n");
+		break;
+	case PFC:
+		ppp_set_pfc(ppp, TRUE);
+		break;
+	case ACFC:
+		ppp_set_acfc(ppp, TRUE);
+		break;
+	default:
+		g_printerr("unhandled option %d\n", option->type);
+	}
+}
+
+struct ppp_packet_handler lcp_packet_handler = {
+	.proto = LCP_PROTOCOL,
+	.handler = pppcp_process_packet,
+};
+
+struct pppcp_action lcp_action = {
+	.this_layer_up =	lcp_up,
+	.this_layer_down = 	lcp_down,
+	.this_layer_started = 	lcp_started,
+	.this_layer_finished =	lcp_finished,
+	.option_scan = 		lcp_option_scan,
+	.option_process = 	lcp_option_process,
+};
+
+void lcp_open(struct pppcp_data *data)
+{
+	if (data == NULL)
+		return;
+
+	/* send an open event to the lcp layer */
+	pppcp_generate_event(data, OPEN, NULL, 0);
+}
+
+void lcp_close(struct pppcp_data *data)
+{
+	if (data == NULL)
+		return;
+
+	/* send a CLOSE  event to the lcp layer */
+	pppcp_generate_event(data, CLOSE, NULL, 0);
+}
+
+void lcp_establish(struct pppcp_data *data)
+{
+	if (data == NULL)
+		return;
+
+	/* send an UP event to the lcp layer */
+	pppcp_generate_event(data, UP, NULL, 0);
+}
+
+void lcp_terminate(struct pppcp_data *data)
+{
+	if (data == NULL)
+		return;
+
+	/* send a DOWN event to the lcp layer */
+	pppcp_generate_event(data, DOWN, NULL, 0);
+}
+
+void lcp_free(struct pppcp_data *lcp)
+{
+	if (lcp == NULL)
+		return;
+
+	/* TBD unregister packet handler */
+
+	pppcp_free(lcp);
+}
+
+struct pppcp_data * lcp_new(GAtPPP *ppp)
+{
+	struct pppcp_data *pppcp;
+	struct ppp_option *option;
+	guint16 codes = LCP_SUPPORTED_CODES;
+
+	pppcp = pppcp_new(ppp, LCP_PROTOCOL, NULL);
+	if (!pppcp) {
+		g_print("Failed to allocate PPPCP struct\n");
+		return NULL;
+	}
+	pppcp_set_valid_codes(pppcp, codes);
+	pppcp->priv = pppcp;
+
+	/* set the actions */
+	pppcp->action = &lcp_action;
+
+	/* add the default config options */
+	option = g_try_malloc0(6);
+	if (option == NULL) {
+		pppcp_free(pppcp);
+		return NULL;
+	}
+	option->type = ACCM;
+	option->length = 6;
+	pppcp_add_config_option(pppcp, option);
+
+	/* register packet handler for LCP protocol */
+	lcp_packet_handler.priv = pppcp;
+	ppp_register_packet_handler(&lcp_packet_handler);
+	return pppcp;
+}
Index: ofono/gatchat/gatppp.c
===================================================================
--- ofono.orig/gatchat/gatppp.c	2010-03-19 12:28:11.820599845 -0700
+++ ofono/gatchat/gatppp.c	2010-03-19 12:29:53.979593793 -0700
@@ -40,6 +40,7 @@
 void g_at_ppp_open(GAtPPP *ppp)
 {
 	/* send an OPEN event to the lcp layer */
+	lcp_open(ppp->lcp);
 }
 
 void g_at_ppp_set_connect_function(GAtPPP *ppp,
@@ -69,6 +70,9 @@
 	/* cleanup modem channel */
 	g_source_remove(ppp->modem_watch);
 	g_io_channel_unref(ppp->modem);
+
+	/* remove lcp */
+	lcp_free(ppp->lcp);
 }
 
 void g_at_ppp_ref(GAtPPP *ppp)
@@ -117,7 +121,7 @@
 	ppp->index = 0;
 
 	/* initialize the lcp state */
-
+	ppp->lcp = lcp_new(ppp);
 
 	/* initialize the autentication state */
 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [patch 4/6] CHAP with MD5 authentication
       [not found] <20100319194705.214150215@linux.intel.com>
                   ` (2 preceding siblings ...)
  2010-03-19 19:46 ` [patch 3/6] LCP support Kristen Carlson Accardi
@ 2010-03-19 19:46 ` Kristen Carlson Accardi
  2010-03-19 19:46 ` [patch 5/6] IP support for PPP Kristen Carlson Accardi
  2010-03-19 19:46 ` [patch 6/6] Allow gsmdial to use gatchat ppp support Kristen Carlson Accardi
  5 siblings, 0 replies; 11+ messages in thread
From: Kristen Carlson Accardi @ 2010-03-19 19:46 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 9702 bytes --]

Implement authentication support with CHAP and MD5 digest
---
 Makefile.am        |    3 
 gatchat/gatppp.c   |   11 ++
 gatchat/gatppp.h   |    2 
 gatchat/ppp.c      |    1 
 gatchat/ppp.h      |   15 +++
 gatchat/ppp_auth.c |  230 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 260 insertions(+), 2 deletions(-)

Index: ofono/Makefile.am
===================================================================
--- ofono.orig/Makefile.am	2010-03-19 12:29:53.977602617 -0700
+++ ofono/Makefile.am	2010-03-19 12:32:03.238468917 -0700
@@ -58,7 +58,8 @@
 				gatchat/gatserver.h gatchat/gatserver.c \
 				gatchat/gatppp.c gatchat/gatppp.h \
 				gatchat/ppp.c gatchat/ppp.h gatchat/ppp_cp.h \
-				gatchat/ppp_cp.c gatchat/ppp_lcp.c
+				gatchat/ppp_cp.c gatchat/ppp_lcp.c \
+				gatchat/ppp_auth.c
 
 udev_files = plugins/ofono.rules
 
Index: ofono/gatchat/gatppp.c
===================================================================
--- ofono.orig/gatchat/gatppp.c	2010-03-19 12:29:53.979593793 -0700
+++ ofono/gatchat/gatppp.c	2010-03-19 12:32:03.239469324 -0700
@@ -43,6 +43,12 @@
 	lcp_open(ppp->lcp);
 }
 
+void g_at_ppp_set_credentials(GAtPPP *ppp, const char *username,
+				const char *passwd)
+{
+	auth_set_credentials(ppp->auth, username, passwd);
+}
+
 void g_at_ppp_set_connect_function(GAtPPP *ppp,
 			       GAtPPPConnectFunc callback, gpointer user_data)
 {
@@ -73,6 +79,9 @@
 
 	/* remove lcp */
 	lcp_free(ppp->lcp);
+
+	/* remove auth */
+	auth_free(ppp->auth);
 }
 
 void g_at_ppp_ref(GAtPPP *ppp)
@@ -124,7 +133,7 @@
 	ppp->lcp = lcp_new(ppp);
 
 	/* initialize the autentication state */
-
+	ppp->auth = auth_new(ppp);
 
 	/* intialize the network state */
 
Index: ofono/gatchat/gatppp.h
===================================================================
--- ofono.orig/gatchat/gatppp.h	2010-03-19 12:28:11.783601764 -0700
+++ ofono/gatchat/gatppp.h	2010-03-19 12:32:03.239469324 -0700
@@ -51,6 +51,8 @@
 void g_at_ppp_shutdown(GAtPPP *ppp);
 void g_at_ppp_ref(GAtPPP *ppp);
 void g_at_ppp_unref(GAtPPP *ppp);
+void g_at_ppp_set_credentials(GAtPPP *ppp, const char *username,
+				const char *passwd);
 #ifdef __cplusplus
 }
 #endif
Index: ofono/gatchat/ppp.h
===================================================================
--- ofono.orig/gatchat/ppp.h	2010-03-19 12:29:53.979593793 -0700
+++ ofono/gatchat/ppp.h	2010-03-19 12:32:03.239469324 -0700
@@ -95,10 +95,20 @@
 #define ppp_proto(packet) \
 	(get_host_short(packet + 2))
 
+struct auth_data {
+	guint16 proto;
+	gpointer proto_data;
+	void (*process_packet)(struct auth_data *data, guint8 *packet);
+	char *username;
+	char *passwd;
+	GAtPPP *ppp;
+};
+
 struct _GAtPPP {
 	gint ref_count;
 	enum ppp_phase phase;
 	struct pppcp_data *lcp;
+	struct auth_data *auth;
 	guint8 buffer[BUFFERSZ];
 	int index;
 	gint mru;
@@ -137,4 +147,9 @@
 void lcp_close(struct pppcp_data *data);
 void lcp_establish(struct pppcp_data *data);
 void lcp_terminate(struct pppcp_data *data);
+void auth_set_credentials(struct auth_data *data, const char *username,
+				const char *passwd);
+void auth_set_proto(struct auth_data *data, guint16 proto, guint8 method);
+struct auth_data *auth_new(GAtPPP *ppp);
+void auth_free(struct auth_data *auth);
 
Index: ofono/gatchat/ppp_auth.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/ppp_auth.c	2010-03-19 12:32:03.240469032 -0700
@@ -0,0 +1,230 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+
+#include "gatppp.h"
+#include "ppp.h"
+
+struct chap_header {
+	guint8 code;
+	guint8 identifier;
+	guint16 length;
+	guint8 data[0];
+} __attribute__((packed));
+
+struct chap_data {
+	guint8 method;
+	struct auth_data *auth;
+};
+
+enum chap_code {
+	CHALLENGE=1,
+	RESPONSE,
+	SUCCESS,
+	FAILURE
+};
+
+void auth_set_credentials(struct auth_data *data, const char *username,
+				const char *passwd)
+{
+	if (data == NULL)
+		return;
+
+	if (data->username)
+		g_free(data->username);
+	if (data->passwd)
+		g_free(data->passwd);
+
+	data->username = g_strdup(username);
+	data->passwd = g_strdup(passwd);
+}
+
+static void chap_process_challenge(struct auth_data *auth, guint8 *packet)
+{
+	struct chap_header *header = (struct chap_header *) packet;
+	struct chap_header *response;
+	struct chap_data *data = auth->proto_data;
+	GChecksum *checksum;
+	gchar *secret = data->auth->passwd;
+	guint16 response_length;
+	struct ppp_header *ppp_packet;
+	gsize digest_len;
+
+	/* create a checksum over id, secret, and challenge */
+	checksum = g_checksum_new(data->method);
+	if (!checksum)
+		return;
+	g_checksum_update(checksum, &header->identifier, 1);
+	g_checksum_update(checksum, (guchar *) secret, strlen(secret));
+	g_checksum_update(checksum, &header->data[1], header->data[0]);
+
+	/* transmit a response packet */
+	/*
+	 * allocate space for the header, the checksum, and the ppp header,
+	 * and the value size byte
+	 */
+	digest_len = g_checksum_type_get_length(data->method);
+	response_length = digest_len + sizeof(*header) + 1;
+	ppp_packet = g_try_malloc0(response_length + 2);
+	if (!ppp_packet)
+		goto challenge_out;
+
+	/* add our protocol information */
+	ppp_packet->proto = htons(CHAP_PROTOCOL);
+	response = (struct chap_header *) &ppp_packet->info;
+	if (response) {
+		response->code = RESPONSE;
+		response->identifier = header->identifier;
+		response->length = htons(response_length);
+		response->data[0] = digest_len;
+		g_checksum_get_digest(checksum, &response->data[1],
+					(gsize *) &response->data[0]);
+		/* leave the name empty? */
+	}
+
+	/* transmit the packet */
+	ppp_transmit(auth->ppp, (guint8 *) ppp_packet, response_length);
+
+challenge_out:
+	g_checksum_free(checksum);
+}
+
+static void chap_process_success(struct auth_data *data, guint8 *packet)
+{
+	ppp_generate_event(data->ppp, PPP_SUCCESS);
+}
+
+static void chap_process_failure(struct auth_data *data, guint8 *packet)
+{
+	struct chap_header *header = (struct chap_header *) packet;
+
+	g_print("Failed to authenticate, message %s\n", header->data);
+}
+
+/*
+ * parse the packet
+ */
+static void chap_process_packet(gpointer priv, guint8 *new_packet)
+{
+	struct auth_data *data = priv;
+	guint8 code = new_packet[0];
+
+	switch (code) {
+	case CHALLENGE:
+		chap_process_challenge(data, new_packet);
+		break;
+	case RESPONSE:
+		g_print("Oops, received RESPONSE, but I've not implemented\n");
+		break;
+	case SUCCESS:
+		chap_process_success(data, new_packet);
+		break;
+	case FAILURE:
+		chap_process_failure(data, new_packet);
+		break;
+	default:
+		g_print("unknown auth code\n");
+		break;
+	}
+}
+
+struct ppp_packet_handler chap_packet_handler = {
+	.proto = CHAP_PROTOCOL,
+	.handler = chap_process_packet,
+};
+
+static void chap_free(struct auth_data *auth)
+{
+	/* TBD unregister protocol handler */
+
+	g_free(auth->proto_data);
+}
+
+static struct chap_data *chap_new(struct auth_data *auth, guint8 method)
+{
+	struct chap_data *data;
+
+	data = g_try_malloc0(sizeof(*data));
+	if (!data)
+		return NULL;
+
+	data->auth = auth;
+	switch (method) {
+	case MD5:
+		data->method = G_CHECKSUM_MD5;
+		break;
+	default:
+		g_print("Unknown method\n");
+	}
+
+	/* register packet handler for CHAP protocol */
+	chap_packet_handler.priv = auth;
+	ppp_register_packet_handler(&chap_packet_handler);
+	return data;
+}
+
+void auth_set_proto(struct auth_data *data, guint16 proto, guint8 method)
+{
+	if (data == NULL)
+		return;
+
+	switch (proto) {
+	case CHAP_PROTOCOL:
+		data->proto_data = (gpointer) chap_new(data, method);
+		break;
+	default:
+		g_print("Unknown auth protocol 0x%x\n", proto);
+	}
+}
+
+void auth_free(struct auth_data *data)
+{
+	if (data == NULL)
+		return;
+
+	chap_free(data);
+	g_free(data);
+}
+
+struct auth_data *auth_new(GAtPPP *ppp)
+{
+	struct auth_data *data;
+
+	data = g_try_malloc0(sizeof(*data));
+	if (!data)
+		return NULL;
+
+	data->ppp = ppp;
+	return data;
+}
+
Index: ofono/gatchat/ppp.c
===================================================================
--- ofono.orig/gatchat/ppp.c	2010-03-19 12:29:53.978616154 -0700
+++ ofono/gatchat/ppp.c	2010-03-19 12:32:03.240469032 -0700
@@ -463,6 +463,7 @@
 	switch (proto) {
 	case CHAP_PROTOCOL:
 		/* get the algorithm */
+		auth_set_proto(ppp->auth, proto, auth_data[2]);
 		break;
 	default:
 		g_printerr("unknown authentication proto\n");


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [patch 5/6] IP support for PPP
       [not found] <20100319194705.214150215@linux.intel.com>
                   ` (3 preceding siblings ...)
  2010-03-19 19:46 ` [patch 4/6] CHAP with MD5 authentication Kristen Carlson Accardi
@ 2010-03-19 19:46 ` Kristen Carlson Accardi
  2010-03-19 19:46 ` [patch 6/6] Allow gsmdial to use gatchat ppp support Kristen Carlson Accardi
  5 siblings, 0 replies; 11+ messages in thread
From: Kristen Carlson Accardi @ 2010-03-19 19:46 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 11977 bytes --]

Implement IPCP support.  Creates a tun interface to pass IP traffic.

---
 Makefile.am       |    2 
 gatchat/gatppp.c  |    1 
 gatchat/ppp.c     |    1 
 gatchat/ppp.h     |   12 +
 gatchat/ppp_net.c |  356 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 371 insertions(+), 1 deletion(-)

Index: ofono/Makefile.am
===================================================================
--- ofono.orig/Makefile.am	2010-03-19 12:32:03.238468917 -0700
+++ ofono/Makefile.am	2010-03-19 12:35:43.583469121 -0700
@@ -59,7 +59,7 @@
 				gatchat/gatppp.c gatchat/gatppp.h \
 				gatchat/ppp.c gatchat/ppp.h gatchat/ppp_cp.h \
 				gatchat/ppp_cp.c gatchat/ppp_lcp.c \
-				gatchat/ppp_auth.c
+				gatchat/ppp_auth.c gatchat/ppp_net.c
 
 udev_files = plugins/ofono.rules
 
Index: ofono/gatchat/ppp.h
===================================================================
--- ofono.orig/gatchat/ppp.h	2010-03-19 12:32:03.239469324 -0700
+++ ofono/gatchat/ppp.h	2010-03-19 12:35:43.584469248 -0700
@@ -104,11 +104,19 @@
 	GAtPPP *ppp;
 };
 
+struct ppp_net_data {
+	GAtPPP *ppp;
+	char *if_name;
+	GIOChannel *channel;
+	struct pppcp_data *ipcp;
+};
+
 struct _GAtPPP {
 	gint ref_count;
 	enum ppp_phase phase;
 	struct pppcp_data *lcp;
 	struct auth_data *auth;
+	struct ppp_net_data *net;
 	guint8 buffer[BUFFERSZ];
 	int index;
 	gint mru;
@@ -152,4 +160,8 @@
 void auth_set_proto(struct auth_data *data, guint16 proto, guint8 method);
 struct auth_data *auth_new(GAtPPP *ppp);
 void auth_free(struct auth_data *auth);
+struct ppp_net_data *ppp_net_new(GAtPPP *ppp);
+void ppp_net_open(struct ppp_net_data *data);
+void ppp_net_free(struct ppp_net_data *data);
+void ppp_net_close(struct ppp_net_data *data);
 
Index: ofono/gatchat/ppp_net.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/ppp_net.c	2010-03-19 12:39:52.668471727 -0700
@@ -0,0 +1,356 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2009-2010  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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+#include <sys/ioctl.h>
+#include <glib.h>
+
+#include "gatutil.h"
+#include "gatppp.h"
+#include "ppp.h"
+
+static void ipcp_free(struct pppcp_data *data);
+
+/* XXX should be maximum IP Packet size */
+#define MAX_PACKET 1500
+#define PPP_IP_PROTO	0x0021
+
+struct ipcp_data {
+	guint8 ip_address[4];
+	guint8 primary_dns[4];
+	guint8 secondary_dns[4];
+	struct pppcp_data *pppcp;
+};
+
+static struct pppcp_data *ipcp_new(GAtPPP *ppp);
+static void ipcp_option_process(gpointer data, gpointer user);
+static guint ipcp_option_scan(struct ppp_option *option, gpointer user);
+
+static void ip_process_packet(gpointer priv, guint8 *packet)
+{
+	struct ppp_net_data *data = priv;
+	GError *error = NULL;
+	GIOStatus status;
+	gsize bytes_written;
+	guint16 len;
+
+	/*
+	 * since ppp_net_open can fail, we need to make sure
+	 * channel is valid
+	 */
+	if (data->channel == NULL)
+		return;
+
+	/* find the length of the packet to transmit */
+	len = get_host_short(&packet[2]);
+	status = g_io_channel_write_chars(data->channel, (gchar *) packet,
+                                          len, &bytes_written, &error);
+}
+
+/*
+ * packets received by the tun interface need to be written to
+ * the modem.  So, just read a packet, write out to the modem
+ *
+ * TBD - how do we know we have a full packet?  Do we care?
+ */
+static gboolean ppp_net_callback(GIOChannel *channel, GIOCondition cond,
+				gpointer userdata)
+{
+	GIOStatus status;
+	gchar buf[MAX_PACKET + 2];
+	gsize bytes_read;
+	GError *error = NULL;
+	struct ppp_header *ppp = (struct ppp_header *) buf;
+	struct ppp_net_data *data = (struct ppp_net_data *) userdata;
+
+	if (cond & G_IO_IN) {
+		/* leave space to add PPP protocol field */
+		status = g_io_channel_read_chars(channel, buf + 2, MAX_PACKET,
+				&bytes_read, &error);
+		if (bytes_read > 0) {
+			ppp->proto = htons(PPP_IP_PROTO);
+			ppp_transmit(data->ppp, (guint8 *) buf, bytes_read);
+		}
+		if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
+			return FALSE;
+	}
+	return TRUE;
+}
+
+void ppp_net_close(struct ppp_net_data *data)
+{
+	/* Not Implemented Yet */
+}
+
+void ppp_net_open(struct ppp_net_data *data)
+{
+	int fd;
+	struct ifreq ifr;
+	GIOChannel *channel;
+	int signal_source;
+	int err;
+
+	if (data == NULL)
+		return;
+
+	/* open a tun interface */
+	fd = open("/dev/net/tun", O_RDWR);
+	if (fd < 0) {
+		g_printerr("error opening tun\n");
+		return;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+	err = ioctl(fd, TUNSETIFF, (void *)&ifr);
+	if (err < 0) {
+		g_printerr("error %d setting ifr\n", err);
+		close(fd);
+		return;
+	}
+	data->if_name = strdup(ifr.ifr_name);
+
+	/* create a channel for reading and writing to this interface */
+	channel = g_io_channel_unix_new(fd);
+	if (!channel) {
+		g_printerr("Error creating I/O Channel to TUN device\n");
+		close(fd);
+		return;
+	}
+	if (!g_at_util_setup_io(channel, G_IO_FLAG_NONBLOCK)) {
+		g_io_channel_unref(channel);
+		return;
+	}
+	data->channel = channel;
+	g_io_channel_set_buffered(channel, FALSE);
+	signal_source = g_io_add_watch(channel,
+			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+			ppp_net_callback, (gpointer) data);
+
+	pppcp_generate_event(data->ipcp, OPEN, NULL, 0);
+
+}
+
+struct ppp_packet_handler ip_packet_handler = {
+	.proto = PPP_IP_PROTO,
+	.handler = ip_process_packet,
+};
+
+void ppp_net_free(struct ppp_net_data *data)
+{
+	/* TBD unregister packet handler */
+
+	/* cleanup tun interface */
+	ppp_net_close(data);
+
+	/* free ipcp data */
+	ipcp_free(data->ipcp);
+
+	/* free self */
+	g_free(data);
+}
+
+struct ppp_net_data *ppp_net_new(GAtPPP *ppp)
+{
+	struct ppp_net_data *data;
+
+	data = g_try_malloc0(sizeof(*data));
+	if (!data)
+		return NULL;
+
+	data->ppp = ppp;
+	data->ipcp = ipcp_new(ppp);
+
+	/* register packet handler for IP protocol */
+	ip_packet_handler.priv = data;
+	ppp_register_packet_handler(&ip_packet_handler);
+	return data;
+}
+
+/****** IPCP support ****************/
+#define IPCP_SUPPORTED_CODES	  ((1 << CONFIGURE_REQUEST) | \
+				  (1 << CONFIGURE_ACK) | \
+				  (1 << CONFIGURE_NAK) | \
+				  (1 << CONFIGURE_REJECT) | \
+				  (1 << TERMINATE_REQUEST) | \
+				  (1 << TERMINATE_ACK) | \
+				  (1 << CODE_REJECT))
+
+#define IPCP_PROTO		0x8021
+
+enum ipcp_option_types {
+	IP_ADDRESSES		= 1,
+	IP_COMPRESSION_PROTO	= 2,
+	IP_ADDRESS		= 3,
+	PRIMARY_DNS_SERVER	= 129,
+	SECONDARY_DNS_SERVER	= 131,
+};
+
+static void ipcp_up(struct pppcp_data *pppcp)
+{
+	struct ipcp_data *data = pppcp->priv;
+	GAtPPP *ppp = pppcp->ppp;
+
+	/* call the connect function */
+	if (ppp->connect_cb)
+		ppp->connect_cb(ppp, G_AT_PPP_CONNECT_SUCCESS,
+				__get_unaligned_long(data->ip_address),
+				__get_unaligned_long(data->primary_dns),
+				__get_unaligned_long(data->secondary_dns),
+				ppp->connect_data);
+}
+
+static void ipcp_down(struct pppcp_data *data)
+{
+	g_print("ipcp down\n");
+
+	/* re-add what default config options we want negotiated */
+}
+
+/*
+ * Tell the protocol to start the handshake
+ */
+static void ipcp_started(struct pppcp_data *data)
+{
+	pppcp_generate_event(data, UP, NULL, 0);
+}
+
+static void ipcp_finished(struct pppcp_data *data)
+{
+	g_print("ipcp finished\n");
+}
+
+struct pppcp_action ipcp_action = {
+	.this_layer_up =	ipcp_up,
+	.this_layer_down = 	ipcp_down,
+	.this_layer_started = 	ipcp_started,
+	.this_layer_finished =	ipcp_finished,
+	.option_scan = 		ipcp_option_scan,
+	.option_process = 	ipcp_option_process,
+};
+
+struct ppp_packet_handler ipcp_packet_handler = {
+	.proto = IPCP_PROTO,
+	.handler = pppcp_process_packet,
+};
+
+/*
+ * Scan the option to see if it is acceptable, unacceptable, or rejected
+ */
+static guint ipcp_option_scan(struct ppp_option *option, gpointer user)
+{
+	switch (option->type) {
+	case IP_ADDRESS:
+	case PRIMARY_DNS_SERVER:
+	case SECONDARY_DNS_SERVER:
+		return OPTION_ACCEPT;
+	default:
+		g_printerr("Unknown ipcp option type %d\n", option->type);
+		return OPTION_REJECT;
+	}
+}
+
+/*
+ * act on an acceptable option
+ */
+static void ipcp_option_process(gpointer data, gpointer user)
+{
+	struct ppp_option *option = data;
+	struct ipcp_data *ipcp = user;
+
+	switch (option->type) {
+	case IP_ADDRESS:
+		memcpy(ipcp->ip_address, option->data, 4);
+		break;
+	case PRIMARY_DNS_SERVER:
+		memcpy(ipcp->primary_dns, option->data, 4);
+		break;
+	case SECONDARY_DNS_SERVER:
+		memcpy(ipcp->secondary_dns, option->data, 4);
+		break;
+	default:
+		g_printerr("Unable to process unknown option %d\n", option->type);
+		break;
+	}
+}
+
+static void ipcp_free(struct pppcp_data *data)
+{
+	struct ipcp_data *ipcp = data->priv;
+
+	/* TBD unregister IPCP packet handler */
+
+	/* free ipcp */
+	g_free(ipcp);
+
+	/* free pppcp */
+	pppcp_free(data);
+}
+
+static struct pppcp_data * ipcp_new(GAtPPP *ppp)
+{
+	struct ipcp_data *data;
+	struct pppcp_data *pppcp;
+	struct ppp_option *ipcp_option;
+
+	data = g_try_malloc0(sizeof(*data));
+	if (!data)
+		return NULL;
+
+	pppcp = pppcp_new(ppp, IPCP_PROTO, data);
+	if (!pppcp) {
+		g_printerr("Failed to allocate PPPCP struct\n");
+		g_free(data);
+		return NULL;
+	}
+	pppcp_set_valid_codes(pppcp, IPCP_SUPPORTED_CODES);
+	pppcp->priv = data;
+
+	/* set the actions */
+	pppcp->action = &ipcp_action;
+
+	/* add the default config options */
+	ipcp_option = g_try_malloc0(6);
+	if (!ipcp_option) {
+		pppcp_free(pppcp);
+		g_free(data);
+		return NULL;
+	}
+	ipcp_option->type = IP_ADDRESS;
+	ipcp_option->length= 6;
+	pppcp_add_config_option(pppcp, ipcp_option);
+
+	/* register packet handler for IPCP protocol */
+	ipcp_packet_handler.priv = pppcp;
+	ppp_register_packet_handler(&ipcp_packet_handler);
+	return pppcp;
+}
Index: ofono/gatchat/gatppp.c
===================================================================
--- ofono.orig/gatchat/gatppp.c	2010-03-19 12:32:03.239469324 -0700
+++ ofono/gatchat/gatppp.c	2010-03-19 12:35:43.584469248 -0700
@@ -136,6 +136,7 @@
 	ppp->auth = auth_new(ppp);
 
 	/* intialize the network state */
+	ppp->net = ppp_net_new(ppp);
 
 	/* start listening for packets from the modem */
 	ppp->modem_watch = g_io_add_watch(modem,
Index: ofono/gatchat/ppp.c
===================================================================
--- ofono.orig/gatchat/ppp.c	2010-03-19 12:32:03.240469032 -0700
+++ ofono/gatchat/ppp.c	2010-03-19 12:35:43.585469096 -0700
@@ -381,6 +381,7 @@
 static void ppp_network(GAtPPP *ppp)
 {
 	/* bring network phase up */
+	ppp_net_open(ppp->net);
 }
 
 static void ppp_transition_phase(GAtPPP *ppp, enum ppp_phase phase)


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [patch 6/6] Allow gsmdial to use gatchat ppp support
       [not found] <20100319194705.214150215@linux.intel.com>
                   ` (4 preceding siblings ...)
  2010-03-19 19:46 ` [patch 5/6] IP support for PPP Kristen Carlson Accardi
@ 2010-03-19 19:46 ` Kristen Carlson Accardi
  2010-03-20 15:35   ` Marcel Holtmann
  5 siblings, 1 reply; 11+ messages in thread
From: Kristen Carlson Accardi @ 2010-03-19 19:46 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 3940 bytes --]

Add option to use PPP to gsmdial.

---
 gatchat/gsmdial.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 87 insertions(+), 3 deletions(-)

Index: ofono/gatchat/gsmdial.c
===================================================================
--- ofono.orig/gatchat/gsmdial.c	2010-03-19 12:28:11.725601078 -0700
+++ ofono/gatchat/gsmdial.c	2010-03-19 12:43:54.427612839 -0700
@@ -29,10 +29,14 @@
 #include <errno.h>
 #include <unistd.h>
 #include <sys/signalfd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <net/if.h>
 
 #include <glib.h>
 #include <gatchat.h>
 #include <gattty.h>
+#include <gatppp.h>
 
 static const char *none_prefix[] = { NULL };
 static const char *cgreg_prefix[] = { "+CGREG:", NULL };
@@ -45,7 +49,11 @@
 static gchar *option_apn = NULL;
 static gint option_offmode = 0;
 static gboolean option_legacy = FALSE;
+static gboolean option_ppp = FALSE;
+static gchar *option_username = NULL;
+static gchar *option_password = NULL;
 
+static GAtPPP *ppp;
 static GAtChat *control;
 static GAtChat *modem;
 static GMainLoop *event_loop;
@@ -220,6 +228,76 @@
 	g_at_chat_send(modem, buf, none_prefix, NULL, NULL, NULL);
 }
 
+static void print_ip_address(const char *label, guint32 ip_addr)
+{
+	struct in_addr addr;
+	char buf[INET_ADDRSTRLEN];
+
+	addr.s_addr = ip_addr;
+
+	if (inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN))
+		g_print("%s: %s\n", label, buf);
+}
+
+static void ppp_connect(GAtPPP *ppp, GAtPPPConnectStatus success,
+			guint32 ip_addr, guint32 dns1, guint32 dns2,
+			gpointer user_data)
+{
+	if (success != G_AT_PPP_CONNECT_SUCCESS) {
+		g_print("Failed to create PPP interface!\n");
+		return;
+	}
+
+	/* print out the negotiated address and dns server */
+	print_ip_address("IP Address", ip_addr);
+	print_ip_address("Primary DNS Server", dns1);
+	print_ip_address("Secondary DNS Server", dns2);
+}
+
+static void ppp_disconnect(GAtPPP *ppp, gpointer user_data)
+{
+	g_print("PPP Link down\n");
+}
+
+static void connect_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+	GIOChannel *channel;
+
+	if (!ok) {
+		g_print("Unable to define context\n");
+		exit(1);
+	}
+
+	if (option_ppp == FALSE)
+		return;
+
+	/* get the data IO channel */
+	channel = g_at_chat_get_channel(modem);
+
+	/*
+	 * shutdown gatchat or else it tries to take all the input
+	 * from the modem and does not let PPP get it.
+	 */
+	g_at_chat_shutdown(control);
+	g_at_chat_shutdown(modem);
+
+	/* open ppp */
+	ppp = g_at_ppp_new(channel);
+	if (!ppp) {
+		g_print("Unable to create PPP object\n");
+		return;
+	}
+	g_at_ppp_set_credentials(ppp, option_username,
+				option_password);
+
+	/* set connect and disconnect callbacks */
+	g_at_ppp_set_connect_function(ppp, ppp_connect, NULL);
+	g_at_ppp_set_disconnect_function(ppp, ppp_disconnect, NULL);
+
+	/* open the ppp connection */
+	g_at_ppp_open(ppp);
+}
+
 static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
 {
 	char buf[64];
@@ -230,9 +308,9 @@
 	}
 
 	if (option_legacy == TRUE) {
-			sprintf(buf, "ATD*99***%u#", option_cid);
-			g_at_chat_send(modem, buf, none_prefix,
-					NULL, NULL, NULL);
+		sprintf(buf, "ATD*99***%u#", option_cid);
+		g_at_chat_send(modem, buf, none_prefix,
+				connect_cb, NULL, NULL);
 	} else {
 		sprintf(buf, "AT+CGACT=1,%u", option_cid);
 		g_at_chat_send(control, buf, none_prefix,
@@ -406,6 +484,12 @@
 				"Specify CFUN offmode" },
 	{ "legacy", 'l', 0, G_OPTION_ARG_NONE, &option_legacy,
 				"Use ATD*99***<cid>#" },
+	{ "ppp", 'P', 0, G_OPTION_ARG_NONE, &option_ppp,
+				"Connect using PPP" },
+	{ "username", 'u', 0, G_OPTION_ARG_STRING, &option_username,
+				"Specify PPP username" },
+	{ "password", 'w', 0, G_OPTION_ARG_STRING, &option_password,
+				"Specifiy PPP password" },
 	{ NULL },
 };
 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [patch 1/6] Add PPP protocol support with HDLC framing
  2010-03-19 19:46 ` [patch 1/6] Add PPP protocol support with HDLC framing Kristen Carlson Accardi
@ 2010-03-20 15:33   ` Marcel Holtmann
  0 siblings, 0 replies; 11+ messages in thread
From: Marcel Holtmann @ 2010-03-20 15:33 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1775 bytes --]

Hi Kristen,

> This patch implements the basic PPP protocol.  LCP, NCP etc. are handled in a
> different patch.
> 
> ---
>  Makefile.am      |    4 
>  gatchat/gatppp.c |  133 ++++++++++++++++
>  gatchat/gatppp.h |   59 +++++++
>  gatchat/ppp.c    |  455 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  gatchat/ppp.h    |  130 +++++++++++++++
>  5 files changed, 780 insertions(+), 1 deletion(-)

please keep the patches whitespace clean. Otherwise you will make it
really hard and complicated for everybody if we have to do whitespace
cleanup in between patches.

Applying: Add PPP protocol support with HDLC framing
/data/devel/ofono/.git/rebase-apply/patch:572: space before tab in indent.
        	if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
/data/devel/ofono/.git/rebase-apply/patch:573: space before tab in indent.
                	return FALSE;
fatal: 2 lines add whitespace errors.

Using an editor that visualizes whitespaces and tabs might help here.

And empty lines at the end of a file. Please remove them and if your
editor is too stupid, then please pick a different editor.

Applying: Add PPP protocol support with HDLC framing
/data/devel/ofono/.git/rebase-apply/patch:166: new blank line at EOF.
+
/data/devel/ofono/.git/rebase-apply/patch:230: new blank line at EOF.
+
fatal: 2 lines add whitespace errors.

Before you submit any patches, you might wanna quickly check with git am
that they still apply. My .gitconfig uses a strict apply policy:

[diff]
	color = auto
	check = true
[apply]
	whitespace = error
[format-patch]
	check = true

Having diff and format-patch color your whitespace damages is always a
good idea. Then you see what is wrong.

Regards

Marcel



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [patch 6/6] Allow gsmdial to use gatchat ppp support
  2010-03-19 19:46 ` [patch 6/6] Allow gsmdial to use gatchat ppp support Kristen Carlson Accardi
@ 2010-03-20 15:35   ` Marcel Holtmann
  0 siblings, 0 replies; 11+ messages in thread
From: Marcel Holtmann @ 2010-03-20 15:35 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 716 bytes --]

Hi Kristen,

> Add option to use PPP to gsmdial.
> 
> ---
>  gatchat/gsmdial.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 87 insertions(+), 3 deletions(-)
> 
> Index: ofono/gatchat/gsmdial.c
> ===================================================================
> --- ofono.orig/gatchat/gsmdial.c	2010-03-19 12:28:11.725601078 -0700
> +++ ofono/gatchat/gsmdial.c	2010-03-19 12:43:54.427612839 -0700
> @@ -29,10 +29,14 @@
>  #include <errno.h>
>  #include <unistd.h>
>  #include <sys/signalfd.h>
> +#include <arpa/inet.h>
> +#include <netinet/in.h>
> +#include <net/if.h>

patches have to be always submitted against the latest tree.

Regards

Marcel



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [patch 4/6] CHAP with MD5 authentication
  2010-03-17  0:13 ` [patch 4/6] CHAP with MD5 authentication Kristen Carlson Accardi
@ 2010-03-17  7:12   ` Marcel Holtmann
  0 siblings, 0 replies; 11+ messages in thread
From: Marcel Holtmann @ 2010-03-17  7:12 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1087 bytes --]

Hi Kristen,

> Implement authentication support with CHAP and MD5 digest
> ---
>  Makefile.am               |    3 
>  gatchat/gatppp.c          |   12 ++
>  gatchat/gatppp.h          |    2 
>  gatchat/gatppp_internal.h |   15 +++
>  gatchat/gatpppauth.c      |  230 ++++++++++++++++++++++++++++++++++++++++++++++

and here we do gatchat/ppp_auth.c.

> ===================================================================
> --- ofono.orig/gatchat/gatppp.h	2010-03-16 15:27:28.906468886 -0700
> +++ ofono/gatchat/gatppp.h	2010-03-16 15:35:51.931601029 -0700
> @@ -51,6 +51,8 @@
>  void g_at_ppp_shutdown(GAtPPP *ppp);
>  void g_at_ppp_ref(GAtPPP *ppp);
>  void g_at_ppp_unref(GAtPPP *ppp);
> +void g_at_ppp_set_credentials(GAtPPP *ppp, gchar *username,
> +				gchar *passwd);

Please don't use gchar. That thing is the most stupid thing the GLib
guys ever did. Even I fell for it some time ago. It is just wrong and
these days even the GLib guys admit that it was an big mistake.

Also these parameters should be const char * actually.

Regards

Marcel



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [patch 4/6] CHAP with MD5 authentication
       [not found] <20100317000824.420232401@linux.intel.com>
@ 2010-03-17  0:13 ` Kristen Carlson Accardi
  2010-03-17  7:12   ` Marcel Holtmann
  0 siblings, 1 reply; 11+ messages in thread
From: Kristen Carlson Accardi @ 2010-03-17  0:13 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 9498 bytes --]

Signed-off-by:  Kristen Carlson Accardi <kristen@linux.intel.com>

Implement authentication support with CHAP and MD5 digest
---
 Makefile.am               |    3 
 gatchat/gatppp.c          |   12 ++
 gatchat/gatppp.h          |    2 
 gatchat/gatppp_internal.h |   15 +++
 gatchat/gatpppauth.c      |  230 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 260 insertions(+), 2 deletions(-)

Index: ofono/Makefile.am
===================================================================
--- ofono.orig/Makefile.am	2010-03-16 15:35:51.922600860 -0700
+++ ofono/Makefile.am	2010-03-16 15:39:53.286468778 -0700
@@ -58,7 +58,8 @@
 				gatchat/gatserver.h gatchat/gatserver.c \
 				gatchat/gatppp_internal.h gatchat/gatpppcp.c \
 				gatchat/gatpppcp.h gatchat/gatppp.c \
-				gatchat/gatppplcp.c gatchat/gatppp.h
+				gatchat/gatppplcp.c gatchat/gatpppauth.c \
+				gatchat/gatppp.h
 
 udev_files = plugins/ofono.rules
 
Index: ofono/gatchat/gatppp.c
===================================================================
--- ofono.orig/gatchat/gatppp.c	2010-03-16 15:35:51.923617679 -0700
+++ ofono/gatchat/gatppp.c	2010-03-16 15:39:53.286468778 -0700
@@ -490,6 +490,9 @@
 
 	/* remove lcp */
 	lcp_free(ppp->lcp);
+
+	/* remove auth */
+	auth_free(ppp->auth);
 }
 
 void g_at_ppp_ref(GAtPPP *ppp)
@@ -508,6 +511,12 @@
 	}
 }
 
+void g_at_ppp_set_credentials(GAtPPP *ppp, gchar *username,
+				gchar *passwd)
+{
+	auth_set_credentials(ppp->auth, username, passwd);
+}
+
 void __ppp_set_auth(GAtPPP *ppp, guint8* auth_data)
 {
 	guint16 proto = ntohs(*(guint16 *)auth_data);
@@ -515,6 +524,7 @@
 	switch(proto) {
 	case CHAP_PROTOCOL:
 		/* get the algorithm */
+		auth_set_proto(ppp->auth, proto, auth_data[2]);
 		break;
 	default:
 		g_printerr("unknown authentication proto\n");
@@ -590,7 +600,7 @@
 	ppp->lcp = lcp_new(ppp);
 
 	/* initialize the autentication state */
-
+	ppp->auth = auth_new(ppp);
 
 	/* intialize the network state */
 
Index: ofono/gatchat/gatppp.h
===================================================================
--- ofono.orig/gatchat/gatppp.h	2010-03-16 15:27:28.906468886 -0700
+++ ofono/gatchat/gatppp.h	2010-03-16 15:35:51.931601029 -0700
@@ -51,6 +51,8 @@
 void g_at_ppp_shutdown(GAtPPP *ppp);
 void g_at_ppp_ref(GAtPPP *ppp);
 void g_at_ppp_unref(GAtPPP *ppp);
+void g_at_ppp_set_credentials(GAtPPP *ppp, gchar *username,
+				gchar *passwd);
 #ifdef __cplusplus
 }
 #endif
Index: ofono/gatchat/gatppp_internal.h
===================================================================
--- ofono.orig/gatchat/gatppp_internal.h	2010-03-16 15:35:51.923617679 -0700
+++ ofono/gatchat/gatppp_internal.h	2010-03-16 15:39:53.286468778 -0700
@@ -64,10 +64,20 @@
 #define ppp_proto(packet) \
 	(ntohs(*((guint16*)(packet+2))))
 
+struct auth_data {
+	guint16 proto;
+	gpointer proto_data;
+	void (*process_packet)(struct auth_data *data, guint8 *packet);
+	GAtPPP *ppp;
+	gchar *username;
+	gchar *passwd;
+};
+
 struct _GAtPPP {
 	gint ref_count;
 	GAtPPPPhase phase;
 	struct pppcp_data *lcp;
+	struct auth_data *auth;
 	guint8 buffer[BUFFERSZ];
 	int index;
 	gint mru;
@@ -104,4 +114,9 @@
 void lcp_close(struct pppcp_data *data);
 void lcp_establish(struct pppcp_data *data);
 void lcp_terminate(struct pppcp_data *data);
+void auth_set_credentials(struct auth_data *data, gchar *username,
+				gchar *passwd);
+void auth_set_proto(struct auth_data *data, guint16 proto, guint8 method);
+struct auth_data *auth_new(GAtPPP *ppp);
+void auth_free(struct auth_data *auth);
 
Index: ofono/gatchat/gatpppauth.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/gatpppauth.c	2010-03-16 15:42:37.556725108 -0700
@@ -0,0 +1,230 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2010  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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+
+#include "gatppp.h"
+#include "gatppp_internal.h"
+
+struct chap_header {
+	guint8 code;
+	guint8 identifier;
+	guint16 length;
+	guint8 data[0];
+};
+
+struct chap_data {
+	guint8 method;
+	struct auth_data *auth;
+};
+
+enum CHAP_CODE {
+	CHALLENGE=1,
+	RESPONSE,
+	SUCCESS,
+	FAILURE
+};
+
+void auth_set_credentials(struct auth_data *data, gchar *username,
+				gchar *passwd)
+{
+	if (data == NULL)
+		return;
+
+	if (data->username)
+		g_free(data->username);
+	if (data->passwd)
+		g_free(data->passwd);
+
+	data->username = g_strdup(username);
+	data->passwd = g_strdup(passwd);
+}
+
+static void chap_process_challenge(struct auth_data *auth, guint8 *packet)
+{
+	struct chap_header *header = (struct chap_header *)packet;
+	struct chap_header *response;
+	struct chap_data *data = auth->proto_data;
+	GChecksum *checksum;
+	gchar *secret = data->auth->passwd;
+	guint16 response_length;
+	guint8 *ppp_packet;
+	gsize digest_len;
+
+	/* create a checksum over id, secret, and challenge */
+	checksum = g_checksum_new(data->method);
+	if (!checksum)
+		return;
+	g_checksum_update(checksum, &header->identifier, 1);
+	g_checksum_update(checksum, (guchar *)secret, strlen(secret));
+	g_checksum_update(checksum, &header->data[1], header->data[0]);
+
+	/* transmit a response packet */
+	/*
+	 * allocate space for the header, the checksum, and the ppp header,
+	 * and the value size byte
+	 */
+	digest_len = g_checksum_type_get_length(data->method);
+	response_length = digest_len + sizeof(*header) + 1;
+	ppp_packet = g_try_malloc0(response_length + 2);
+	if (!ppp_packet)
+		goto challenge_out;
+
+	/* add our protocol information */
+	*((guint16 *)ppp_packet) = htons(CHAP_PROTOCOL);
+	response = (struct chap_header *)(ppp_packet+2);
+	if (response) {
+		response->code = RESPONSE;
+		response->identifier = header->identifier;
+		response->length = htons(response_length);
+		response->data[0] = digest_len;
+		g_checksum_get_digest(checksum, &response->data[1],
+					(gsize *)&response->data[0]);
+		/* leave the name empty? */
+	}
+
+	/* transmit the packet */
+	__ppp_transmit(auth->ppp, ppp_packet, response_length);
+
+challenge_out:
+	g_checksum_free(checksum);
+}
+
+static void chap_process_success(struct auth_data *data, guint8 *packet)
+{
+	__ppp_generate_event(data->ppp, PPP_SUCCESS);
+}
+
+static void chap_process_failure(struct auth_data *data, guint8 *packet)
+{
+	struct chap_header *header = (struct chap_header *)packet;
+
+	g_print("Failed to authenticate, message %s\n", header->data);
+}
+
+/*
+ * parse the packet
+ */
+static void chap_process_packet(gpointer priv, guint8 *new_packet)
+{
+	struct auth_data *data = priv;
+	guint8 code = new_packet[0];
+
+	switch(code) {
+	case CHALLENGE:
+		chap_process_challenge(data, new_packet);
+		break;
+	case RESPONSE:
+		g_print("Oops, received RESPONSE, but I've not implemented\n");
+		break;
+	case SUCCESS:
+		chap_process_success(data, new_packet);
+		break;
+	case FAILURE:
+		chap_process_failure(data, new_packet);
+		break;
+	default:
+		g_print("unknown auth code\n");
+		break;
+	}
+}
+
+struct ppp_packet_handler chap_packet_handler = {
+	.proto = CHAP_PROTOCOL,
+	.handler = chap_process_packet,
+};
+
+static void chap_free(struct auth_data *auth)
+{
+	/* TBD unregister protocol handler */
+
+	g_free(auth->proto_data);
+}
+
+static struct chap_data *chap_new(struct auth_data *auth, guint8 method)
+{
+	struct chap_data *data;
+
+	data = g_try_malloc0(sizeof(*data));
+	if (!data)
+		return NULL;
+
+	data->auth = auth;
+	switch(method) {
+	case MD5:
+		data->method = G_CHECKSUM_MD5;
+		break;
+	default:
+		g_print("Unknown method\n");
+	}
+
+	/* register packet handler for CHAP protocol */
+	chap_packet_handler.priv = auth;
+	__ppp_register_packet_handler(&chap_packet_handler);
+	return data;
+}
+
+void auth_set_proto(struct auth_data *data, guint16 proto, guint8 method)
+{
+	if (data == NULL)
+		return;
+
+	switch(proto) {
+	case CHAP_PROTOCOL:
+		data->proto_data = (gpointer) chap_new(data, method);
+		break;
+	default:
+		g_print("Unknown auth protocol 0x%x\n", proto);
+	}
+}
+
+void auth_free(struct auth_data *data)
+{
+	if (data == NULL)
+		return;
+
+	chap_free(data);
+	g_free(data);
+}
+
+struct auth_data *auth_new(GAtPPP *ppp)
+{
+	struct auth_data *data;
+
+	data = g_try_malloc0(sizeof(*data));
+	if (!data)
+		return NULL;
+
+	data->ppp = ppp;
+	return data;
+}
+


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [patch 4/6] CHAP with MD5 authentication
       [not found] <20100311214022.838696145@linux.intel.com>
@ 2010-03-11 22:00 ` kristen
  0 siblings, 0 replies; 11+ messages in thread
From: kristen @ 2010-03-11 22:00 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 9623 bytes --]

Implement authentication support with CHAP and MD5 digest
Index: ofono/Makefile.am
===================================================================
--- ofono.orig/Makefile.am	2010-03-10 17:01:56.687955124 -0800
+++ ofono/Makefile.am	2010-03-10 17:03:01.695955140 -0800
@@ -58,7 +58,8 @@
 				gatchat/gatserver.h gatchat/gatserver.c \
 				gatchat/gatppp_internal.h gatchat/gatpppcp.c \
 				gatchat/gatpppcp.h gatchat/gatppp.c \
-				gatchat/gatppplcp.c gatchat/gatppp.h
+				gatchat/gatppplcp.c gatchat/gatpppauth.c \
+				gatchat/gatppp.h
 
 udev_files = plugins/ofono.rules
 
Index: ofono/gatchat/gatppp.c
===================================================================
--- ofono.orig/gatchat/gatppp.c	2010-03-10 17:01:56.687955124 -0800
+++ ofono/gatchat/gatppp.c	2010-03-10 17:03:01.696955547 -0800
@@ -390,6 +390,7 @@
 static void ppp_network(struct ppp_link *link)
 {
 	/* bring network phase up */
+	net_open(link->net);
 }
 
 static void ppp_transition_phase(struct ppp_link *link, guint phase)
@@ -492,6 +493,9 @@
 
 	/* remove lcp */
 	lcp_free(link->lcp);
+
+	/* remove auth */
+	auth_free(link->auth);
 }
 
 void g_at_ppp_ref(struct ppp_link *link)
@@ -510,6 +514,12 @@
 	}
 }
 
+void g_at_ppp_set_credentials(struct ppp_link *link, gchar *username,
+				gchar *passwd)
+{
+	auth_set_credentials(link->auth, username, passwd);
+}
+
 void __ppp_set_auth(struct ppp_link *link, guint8* auth_data)
 {
 	guint16 proto = ntohs(*(guint16 *)auth_data);
@@ -517,6 +527,7 @@
 	switch(proto) {
 	case CHAP_PROTOCOL:
 		/* get the algorithm */
+		auth_set_proto(link->auth, proto, auth_data[2]);
 		break;
 	default:
 		g_printerr("unknown authentication proto\n");
@@ -594,9 +605,10 @@
 	link->lcp = lcp_new(link);
 
 	/* initialize the autentication state */
-
+	link->auth = auth_new(link);
 
 	/* intialize the network state */
+	link->net = net_new(link);
 
 	/* start listening for packets from the modem */
 	signal_source = g_io_add_watch(modem,
Index: ofono/gatchat/gatppp.h
===================================================================
--- ofono.orig/gatchat/gatppp.h	2010-03-10 17:01:56.688955112 -0800
+++ ofono/gatchat/gatppp.h	2010-03-10 17:03:01.696955547 -0800
@@ -27,6 +27,7 @@
 #endif
 
 struct ppp_link;
+struct auth_data;
 
 enum PPP_CONNECT_STATUS {
 	PPP_CONNECT_SUCCESS,
@@ -44,6 +45,7 @@
 	gint ref_count;
 	guint phase;
 	struct pppcp_data *lcp;
+	struct auth_data *auth;
 	guint8 *buffer;
 	int index;
 	gint mru;
@@ -74,6 +76,8 @@
 void g_at_ppp_shutdown(struct ppp_link *link);
 void g_at_ppp_ref(struct ppp_link *link);
 void g_at_ppp_unref(struct ppp_link *link);
+void g_at_ppp_set_credentials(struct ppp_link *link, gchar *username,
+				gchar *passwd);
 #ifdef __cplusplus
 }
 #endif
Index: ofono/gatchat/gatppp_internal.h
===================================================================
--- ofono.orig/gatchat/gatppp_internal.h	2010-03-10 17:01:56.688955112 -0800
+++ ofono/gatchat/gatppp_internal.h	2010-03-10 17:03:01.697955395 -0800
@@ -66,6 +66,15 @@
 	gpointer priv;
 };
 
+struct auth_data {
+	guint16 proto;
+	gpointer proto_data;
+	void (*process_packet)(struct auth_data *data, guint8 *packet);
+	struct ppp_link *link;
+	gchar *username;
+	gchar *passwd;
+};
+
 #define ppp_generate_event(l, e) \
 	__ppp_generate_event(l, e)
 
@@ -97,6 +106,11 @@
 void lcp_close(struct pppcp_data *data);
 void lcp_establish(struct pppcp_data *data);
 void lcp_terminate(struct pppcp_data *data);
+void auth_set_credentials(struct auth_data *data, gchar *username,
+				gchar *passwd);
+void auth_set_proto(struct auth_data *data, guint16 proto, guint8 method);
+struct auth_data *auth_new(struct ppp_link *link);
+void auth_free(struct auth_data *auth);
 #ifdef __cplusplus
 }
 #endif
Index: ofono/gatchat/gatpppauth.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ofono/gatchat/gatpppauth.c	2010-03-10 17:03:01.697955395 -0800
@@ -0,0 +1,219 @@
+/*
+ *
+ *  PPP library with GLib integration
+ *
+ *  Copyright (C) 2010  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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+
+#include "gatppp.h"
+#include "gatppp_internal.h"
+
+struct chap_header {
+	guint8 code;
+	guint8 identifier;
+	guint16 length;
+	guint8 data[0];
+};
+
+struct chap_data {
+	guint8 method;
+	struct auth_data *auth;
+};
+
+enum CHAP_CODE {
+	CHALLENGE=1,
+	RESPONSE,
+	SUCCESS,
+	FAILURE
+};
+
+void auth_set_credentials(struct auth_data *data, gchar *username,
+				gchar *passwd)
+{
+	if (data->username)
+		g_free(data->username);
+	if (data->passwd)
+		g_free(data->passwd);
+
+	data->username = g_strdup(username);
+	data->passwd = g_strdup(passwd);
+}
+
+static void chap_process_challenge(struct auth_data *auth, guint8 *packet)
+{
+	struct chap_header *header = (struct chap_header *)packet;
+	struct chap_header *response;
+	struct chap_data *data = auth->proto_data;
+	GChecksum *checksum;
+	gchar *secret = data->auth->passwd;
+	guint16 response_length;
+	guint8 *ppp_packet;
+	gsize digest_len;
+
+	/* create a checksum over id, secret, and challenge */
+	checksum = g_checksum_new(data->method);
+	if (!checksum)
+		return;
+	g_checksum_update(checksum, &header->identifier, 1);
+	g_checksum_update(checksum, (guchar *)secret, strlen(secret));
+	g_checksum_update(checksum, &header->data[1], header->data[0]);
+
+	/* transmit a response packet */
+	/*
+	 * allocate space for the header, the checksum, and the ppp header,
+	 * and the value size byte
+	 */
+	digest_len = g_checksum_type_get_length(data->method);
+	response_length = digest_len + sizeof(*header) + 1;
+	ppp_packet = g_malloc0(response_length + 2);
+	if (!ppp_packet)
+		goto challenge_out;
+
+	/* add our protocol information */
+	*((guint16 *)ppp_packet) = htons(CHAP_PROTOCOL);
+	response = (struct chap_header *)(ppp_packet+2);
+	if (response) {
+		response->code = RESPONSE;
+		response->identifier = header->identifier;
+		response->length = htons(response_length);
+		response->data[0] = digest_len;
+		g_checksum_get_digest(checksum, &response->data[1],
+					(gsize *)&response->data[0]);
+		/* leave the name empty? */
+	}
+
+	/* transmit the packet */
+	ppp_transmit(auth->link, ppp_packet, response_length);
+
+challenge_out:
+	g_checksum_free(checksum);
+}
+
+static void chap_process_success(struct auth_data *data, guint8 *packet)
+{
+	ppp_generate_event(data->link, PPP_SUCCESS);
+}
+
+static void chap_process_failure(struct auth_data *data, guint8 *packet)
+{
+	struct chap_header *header = (struct chap_header *)packet;
+
+	g_print("Failed to authenticate, message %s\n", header->data);
+}
+
+/*
+ * parse the packet
+ */
+static void chap_process_packet(gpointer priv, guint8 *new_packet)
+{
+	struct auth_data *data = (struct auth_data *)priv;
+	guint8 code = new_packet[0];
+
+	switch(code) {
+	case CHALLENGE:
+		chap_process_challenge(data, new_packet);
+		break;
+	case RESPONSE:
+		g_print("Oops, received RESPONSE, but I've not implemented\n");
+		break;
+	case SUCCESS:
+		chap_process_success(data, new_packet);
+		break;
+	case FAILURE:
+		chap_process_failure(data, new_packet);
+		break;
+	default:
+		g_print("unknown auth code\n");
+		break;
+	}
+}
+
+struct ppp_packet_handler chap_packet_handler = {
+	.proto = CHAP_PROTOCOL,
+	.handler = chap_process_packet,
+};
+
+static void chap_free(struct auth_data *auth)
+{
+	/* TBD unregister protocol handler */
+
+	g_free(auth->proto_data);
+}
+
+static struct chap_data *chap_new(struct auth_data *auth, guint8 method)
+{
+	struct chap_data *data;
+
+	data = g_malloc0(sizeof(*data));
+
+	if (data) {
+		data->auth = auth;
+		switch(method) {
+		case MD5:
+			data->method = G_CHECKSUM_MD5;
+			break;
+		default:
+			g_print("Unknown method\n");
+		}
+
+		/* register packet handler for CHAP protocol */
+		chap_packet_handler.priv = auth;
+		ppp_register_packet_handler(&chap_packet_handler);
+	}
+	return data;
+}
+
+void auth_set_proto(struct auth_data *data, guint16 proto, guint8 method)
+{
+	switch(proto) {
+	case CHAP_PROTOCOL:
+		data->proto_data = (gpointer) chap_new(data, method);
+		break;
+	default:
+		g_print("Unknown auth protocol 0x%x\n", proto);
+	}
+}
+
+void auth_free(struct auth_data *data)
+{
+	chap_free(data);
+	g_free(data);
+}
+
+struct auth_data *auth_new(struct ppp_link *link)
+{
+	struct auth_data *data;
+
+	data = g_malloc0(sizeof(*data));
+	if (data)
+		data->link = link;
+	return data;
+}
+


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2010-03-20 15:35 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20100319194705.214150215@linux.intel.com>
2010-03-19 19:46 ` [patch 1/6] Add PPP protocol support with HDLC framing Kristen Carlson Accardi
2010-03-20 15:33   ` Marcel Holtmann
2010-03-19 19:46 ` [patch 2/6] Generic PPP control protocol Kristen Carlson Accardi
2010-03-19 19:46 ` [patch 3/6] LCP support Kristen Carlson Accardi
2010-03-19 19:46 ` [patch 4/6] CHAP with MD5 authentication Kristen Carlson Accardi
2010-03-19 19:46 ` [patch 5/6] IP support for PPP Kristen Carlson Accardi
2010-03-19 19:46 ` [patch 6/6] Allow gsmdial to use gatchat ppp support Kristen Carlson Accardi
2010-03-20 15:35   ` Marcel Holtmann
     [not found] <20100317000824.420232401@linux.intel.com>
2010-03-17  0:13 ` [patch 4/6] CHAP with MD5 authentication Kristen Carlson Accardi
2010-03-17  7:12   ` Marcel Holtmann
     [not found] <20100311214022.838696145@linux.intel.com>
2010-03-11 22:00 ` kristen

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.