[PATCH 3/3] ppp: use GAtHDLC

Kristen Carlson Accardi kristen at linux.intel.com
Sat Apr 17 11:15:35 PDT 2010


---
 gatchat/gatppp.c   |  347 +++++++++-------------------------------------------
 gatchat/ppp.h      |   11 ++
 gatchat/ppp_auth.c |    2 +-
 gatchat/ppp_cp.c   |    6 +-
 gatchat/ppp_net.c  |    3 +-
 5 files changed, 75 insertions(+), 294 deletions(-)

diff --git a/gatchat/gatppp.c b/gatchat/gatppp.c
index e1e49e6..5b6ba4e 100644
--- a/gatchat/gatppp.c
+++ b/gatchat/gatppp.c
@@ -34,6 +34,7 @@
 
 #include <glib.h>
 
+#include "gathdlc.h"
 #include "gatutil.h"
 #include "gatppp.h"
 #include "crc-ccitt.h"
@@ -41,10 +42,6 @@
 
 #define DEFAULT_MRU	1500
 
-#define BUFFERSZ	(DEFAULT_MRU * 2)
-
-#define PPP_ESC		0x7d
-#define PPP_FLAG_SEQ 	0x7e
 #define PPP_ADDR_FIELD	0xff
 #define PPP_CTRL	0x03
 
@@ -55,24 +52,19 @@ struct _GAtPPP {
 	struct pppcp_data *ipcp;
 	struct ppp_net *net;
 	struct ppp_chap *chap;
-	guint8 buffer[BUFFERSZ];
-	int index;
 	gint mru;
 	char username[256];
 	char password[256];
 	guint32 xmit_accm[8];
 	guint32 recv_accm;
-	GIOChannel *modem;
 	GAtPPPConnectFunc connect_cb;
 	gpointer connect_data;
 	GAtDisconnectFunc disconnect_cb;
 	gpointer disconnect_data;
-	gint read_watch;
-	gint write_watch;
 	GAtDebugFunc debugf;
 	gpointer debug_data;
 	int record_fd;
-	GQueue *xmit_queue;
+	GAtHDLC *hdlc;
 };
 
 void ppp_debug(GAtPPP *ppp, const char *str)
@@ -91,81 +83,59 @@ struct frame_buffer {
 	guint8 bytes[0];
 };
 
+static void ppp_record(GAtPPP *ppp, gboolean in, guint8 *data, guint16 length)
+{
+	guint16 len = htons(length);
+	guint32 ts;
+	struct timeval now;
+	unsigned char id;
+	int err;
+
+	if (ppp->record_fd < 0)
+		return;
+
+	gettimeofday(&now, NULL);
+	ts = htonl(now.tv_sec & 0xffffffff);
+
+	id = 0x07;
+	err = write(ppp->record_fd, &id, 1);
+	err = write(ppp->record_fd, &ts, 4);
+
+	id = in ? 0x02 : 0x01;
+	err = write(ppp->record_fd, &id, 1);
+	err = write(ppp->record_fd, &len, 2);
+	err = write(ppp->record_fd, data, length);
+}
+
 /*
  * 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)
+static gboolean ppp_escape(gpointer user_data, guint8 c, gboolean lcp)
 {
+	GAtPPP *ppp = user_data;
+
 	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)
+static gboolean ppp_hdlc_scan(gpointer user_data, const unsigned char *data)
 {
-	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;
-}
+	guint16 proto = ppp_proto(data);
 
-static struct frame_buffer *ppp_encode(GAtPPP *ppp, guint8 *data, int len)
-{
-	int pos = 0;
-	int i = 0;
-	guint16 fcs = PPPINITFCS16;
-	guint16 proto = get_host_short(data);
-	gboolean lcp = (proto == LCP_PROTOCOL);
-	guint8 *frame;
-	struct frame_buffer *fb =
-		g_try_malloc0(BUFFERSZ + sizeof(struct frame_buffer));
-
-	if (!fb)
-		return NULL;
-	frame = fb->bytes;
-
-	/* copy in the HDLC framing */
-	frame[pos++] = PPP_FLAG_SEQ;
-
-	/* from here till end flag, calculate FCS over each character */
-	fcs = crc_ccitt_byte(fcs, PPP_ADDR_FIELD);
-	ppp_put(ppp, frame, &pos, PPP_ADDR_FIELD, lcp);
-	fcs = crc_ccitt_byte(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 = crc_ccitt_byte(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;
-
-	fb->len = pos;
-	return fb;
+	if (proto == LCP_PROTOCOL)
+		return TRUE;
+	return FALSE;
 }
 
-/* called when we have received a complete ppp frame */
-static void ppp_recv(GAtPPP *ppp, struct frame_buffer *frame)
+static void ppp_hdlc_recv(const unsigned char *data, gsize size, gpointer user_data)
 {
-	guint16 protocol = ppp_proto(frame->bytes);
-	guint8 *packet = ppp_info(frame->bytes);
+	GAtPPP *ppp = user_data;
+	guint16 protocol = ppp_proto(data);
+	guint8 *packet = (guint8 *) ppp_info(data);
+
+	ppp_record(ppp, TRUE, (guint8 *) data, size);
 
 	switch (protocol) {
 	case PPP_IP_PROTO:
@@ -186,144 +156,18 @@ static void ppp_recv(GAtPPP *ppp, struct frame_buffer *frame)
 		}
 		/* fall through */
 	default:
-		pppcp_send_protocol_reject(ppp->lcp, frame->bytes, frame->len);
+		pppcp_send_protocol_reject(ppp->lcp, (guint8 *) data, size);
 		break;
 	};
 }
 
-static struct frame_buffer *ppp_decode(GAtPPP *ppp, guint8 *frame)
+static gboolean ppp_recv_escape(gpointer user_data, guint8 c)
 {
-	guint8 *data;
-	guint pos;
-	int i;
-	guint16 fcs;
-	struct frame_buffer *fb;
-
-	fb = g_try_malloc0(sizeof(struct frame_buffer) + ppp->mru + 10);
-	if (!fb)
-		return NULL;
-	data = fb->bytes;
-
-	/* skip the first flag char */
-	pos = 1;
-
-	fcs = PPPINITFCS16;
-	i = 0;
-
-	while (frame[pos] != PPP_FLAG_SEQ) {
-		/* Skip the characters in receive ACCM */
-		if (frame[pos] < 0x20 &&
-				(ppp->recv_accm & (1 << frame[pos])) != 0) {
-			pos++;
-			continue;
-		}
-
-		/* scan for escape character */
-		if (frame[pos] == PPP_ESC) {
-			/* skip that char */
-			pos++;
-			data[i] = frame[pos] ^ 0x20;
-		} else
-			data[i] = frame[pos];
-
-		fcs = crc_ccitt_byte(fcs, data[i]);
-
-		i++; pos++;
-	}
+	GAtPPP *ppp = user_data;
 
-	fb->len = i;
-
-	/* see if we have a good FCS */
-	if (fcs != PPPGOODFCS16) {
-		g_free(fb);
-		return NULL;
-	}
-
-	return fb;
-}
-
-static void ppp_feed(GAtPPP *ppp, guint8 *data, gsize len)
-{
-	guint pos = 0;
-	struct frame_buffer *frame;
-
-	/* collect bytes until we detect we have received a complete frame */
-	/* examine the data.  If we are at 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);
-				if (frame) {
-					/* process receive frame */
-					ppp_recv(ppp, frame);
-					g_free(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];
-	}
-}
-
-static void ppp_record(GAtPPP *ppp, gboolean in, guint8 *data, guint16 length)
-{
-	guint16 len = htons(length);
-	guint32 ts;
-	struct timeval now;
-	unsigned char id;
-	int err;
-
-	if (ppp->record_fd < 0)
-		return;
-
-	gettimeofday(&now, NULL);
-	ts = htonl(now.tv_sec & 0xffffffff);
-
-	id = 0x07;
-	err = write(ppp->record_fd, &id, 1);
-	err = write(ppp->record_fd, &ts, 4);
-
-	id = in ? 0x02 : 0x01;
-	err = write(ppp->record_fd, &id, 1);
-	err = write(ppp->record_fd, &len, 2);
-	err = write(ppp->record_fd, data, length);
-}
-
-static gboolean ppp_read_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))
-		return FALSE;
-
-	if (cond & G_IO_IN) {
-		status = g_io_channel_read_chars(channel, buf, 256,
-				&bytes_read, &error);
-		if (bytes_read > 0) {
-			ppp_record(ppp, TRUE, (guint8 *) buf, bytes_read);
-			ppp_feed(ppp, (guint8 *) buf, bytes_read);
-		}
-		if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
-			return FALSE;
-	}
-
-	return TRUE;
+	if (c < 0x20 && (ppp->recv_accm & (1 << c)) != 0)
+		return TRUE;
+	return FALSE;
 }
 
 static void ppp_dead(GAtPPP *ppp)
@@ -371,12 +215,6 @@ void ppp_enter_phase(GAtPPP *ppp, enum ppp_phase phase)
 	}
 }
 
-static void read_watcher_destroy_notify(GAtPPP *ppp)
-{
-	ppp->read_watch = 0;
-	pppcp_signal_down(ppp->lcp);
-}
-
 void ppp_set_auth(GAtPPP *ppp, const guint8* auth_data)
 {
 	guint16 proto = get_host_short(auth_data);
@@ -540,13 +378,7 @@ void g_at_ppp_unref(GAtPPP *ppp)
 	if (ppp->record_fd > fileno(stderr))
 		close(ppp->record_fd);
 
-	/* cleanup queue */
-	g_queue_free(ppp->xmit_queue);
-
-	/* cleanup modem channel */
-	g_source_remove(ppp->read_watch);
-	g_source_remove(ppp->write_watch);
-	g_io_channel_unref(ppp->modem);
+	g_at_hdlc_unref(ppp->hdlc);
 
 	lcp_free(ppp->lcp);
 	ppp_chap_free(ppp->chap);
@@ -566,11 +398,15 @@ GAtPPP *g_at_ppp_new(GIOChannel *modem)
 	if (!ppp)
 		return NULL;
 
-	if (!g_at_util_setup_io(modem, G_IO_FLAG_NONBLOCK)) {
+	ppp->hdlc = g_at_hdlc_new(modem);
+	if (ppp->hdlc == NULL) {
 		g_free(ppp);
 		return NULL;
 	}
-	g_io_channel_set_buffered(modem, FALSE);
+	g_at_hdlc_set_receive(ppp->hdlc, ppp_hdlc_recv, ppp);
+	g_at_hdlc_set_recv_escape(ppp->hdlc, ppp_recv_escape, ppp);
+	g_at_hdlc_set_send_escape(ppp->hdlc, ppp_escape, ppp);
+	g_at_hdlc_set_scan(ppp->hdlc, ppp_hdlc_scan, ppp);
 
 	ppp->ref_count = 1;
 
@@ -580,70 +416,16 @@ GAtPPP *g_at_ppp_new(GIOChannel *modem)
 	ppp->xmit_accm[0] = ~0U;
 	ppp->xmit_accm[3] = 0x60000000; /* 0x7d, 0x7e */
 
-	ppp->index = 0;
-
-	/* intialize the queue */
-	ppp->xmit_queue = g_queue_new();
-
 	/* initialize the lcp state */
 	ppp->lcp = lcp_new(ppp);
 
 	/* initialize IPCP state */
 	ppp->ipcp = ipcp_new(ppp);
-
-	/* start listening for packets from the modem */
-	ppp->read_watch = g_io_add_watch_full(modem, G_PRIORITY_DEFAULT,
-				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-				ppp_read_cb, ppp,
-				(GDestroyNotify)read_watcher_destroy_notify);
-
-	ppp->modem = modem;
 	ppp->record_fd = -1;
 
 	return ppp;
 }
 
-static gboolean ppp_xmit_cb(GIOChannel *channel, GIOCondition cond,
-				gpointer data)
-{
-	GAtPPP *ppp = data;
-	struct frame_buffer *fb;
-	GError *error = NULL;
-	GIOStatus status;
-	gsize bytes_written;
-
-	if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
-		return FALSE;
-
-	if (cond & G_IO_OUT) {
-		while ((fb = g_queue_peek_head(ppp->xmit_queue))) {
-			status = g_io_channel_write_chars(ppp->modem,
-					(gchar *) fb->bytes, fb->len,
-					&bytes_written, &error);
-			if (status != G_IO_STATUS_NORMAL &&
-				status != G_IO_STATUS_AGAIN)
-				return FALSE;
-
-			if (bytes_written < fb->len)
-				return TRUE;
-
-			ppp_record(ppp, FALSE, fb->bytes, bytes_written);
-			g_free(g_queue_pop_head(ppp->xmit_queue));
-		}
-	}
-	return FALSE;
-}
-
-static void ppp_xmit_destroy_notify(gpointer destroy_data)
-{
-	GAtPPP *ppp = destroy_data;
-
-	ppp->write_watch = 0;
-
-	if (ppp->phase == PPP_PHASE_DEAD)
-		ppp_dead(ppp);
-}
-
 /*
  * transmit out through the lower layer interface
  *
@@ -651,22 +433,11 @@ static void ppp_xmit_destroy_notify(gpointer destroy_data)
  */
 void ppp_transmit(GAtPPP *ppp, guint8 *packet, guint infolen)
 {
-	struct frame_buffer *fb;
-
-	/*
-	 * do the octet stuffing.  Add 2 bytes to the infolen to
-	 * include the protocol field.
-	 */
-	fb = ppp_encode(ppp, packet, infolen + 2);
-	if (!fb) {
-		g_printerr("Failed to encode packet to transmit\n");
-		return;
-	}
-	/* push decoded frame onto xmit queue */
-	g_queue_push_tail(ppp->xmit_queue, fb);
+	struct ppp_header *header = (struct ppp_header *) packet;
+	gsize len = infolen + sizeof(struct ppp_header);
 
-	/* transmit this whenever we can write without blocking */
-	ppp->write_watch = g_io_add_watch_full(ppp->modem, G_PRIORITY_DEFAULT,
-				G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-				ppp_xmit_cb, ppp, ppp_xmit_destroy_notify);
+	header->address = PPP_ADDR_FIELD;
+	header->control = PPP_CTRL;
+	g_at_hdlc_send(ppp->hdlc, packet, len);
+	ppp_record(ppp, FALSE, packet, len);
 }
diff --git a/gatchat/ppp.h b/gatchat/ppp.h
index a8a0486..c41bb05 100644
--- a/gatchat/ppp.h
+++ b/gatchat/ppp.h
@@ -39,6 +39,8 @@ struct ppp_chap;
 struct ppp_net;
 
 struct ppp_header {
+	guint8 address;
+	guint8 control;
 	guint16 proto;
 	guint8 info[0];
 } __attribute__((packed));
@@ -84,6 +86,15 @@ static inline void __put_unaligned_short(void *p, guint16 val)
 #define ppp_proto(packet) \
 	(get_host_short(packet + 2))
 
+#define ppp_hdlc_proto(packet) \
+	(get_host_short(packet + 4))
+
+#define ppp_hdlc_info(packet) \
+	(packet + 6)
+
+#define ppp_hdlc_packet(packet) \
+	((guint8 *) packet + 2)
+
 /* LCP related functions */
 struct pppcp_data *lcp_new(GAtPPP *ppp);
 void lcp_free(struct pppcp_data *lcp);
diff --git a/gatchat/ppp_auth.c b/gatchat/ppp_auth.c
index 57203ab..b8c0628 100644
--- a/gatchat/ppp_auth.c
+++ b/gatchat/ppp_auth.c
@@ -83,7 +83,7 @@ static void chap_process_challenge(struct ppp_chap *chap, guint8 *packet)
 	 */
 	digest_len = g_checksum_type_get_length(chap->method);
 	response_length = digest_len + sizeof(*header) + 1;
-	ppp_packet = g_try_malloc0(response_length + 2);
+	ppp_packet = g_try_malloc0(response_length + sizeof(struct ppp_header));
 	if (!ppp_packet)
 		goto challenge_out;
 
diff --git a/gatchat/ppp_cp.c b/gatchat/ppp_cp.c
index 6cd3681..ce8c94a 100644
--- a/gatchat/ppp_cp.c
+++ b/gatchat/ppp_cp.c
@@ -61,10 +61,8 @@ static const char *pppcp_event_strings[] = {
 	g_free(str); \
 } while (0);
 
-#define PPP_HEADROOM	2
-
 #define pppcp_to_ppp_packet(p) \
-	(((guint8 *) p) - PPP_HEADROOM)
+	(((guint8 *) p) - sizeof(struct ppp_header))
 
 #define INITIAL_RESTART_TIMEOUT	3	/* restart interval in seconds */
 #define MAX_TERMINATE		2
@@ -206,7 +204,7 @@ static struct pppcp_packet *pppcp_packet_new(struct pppcp_data *data,
 	struct ppp_header *ppp_packet;
 	guint16 packet_length = bufferlen + sizeof(*packet);
 
-	ppp_packet = g_try_malloc0(packet_length + 2);
+	ppp_packet = g_try_malloc0(packet_length + sizeof(struct ppp_header));
 	if (!ppp_packet)
 		return NULL;
 
diff --git a/gatchat/ppp_net.c b/gatchat/ppp_net.c
index 325e859..9fbd1d7 100644
--- a/gatchat/ppp_net.c
+++ b/gatchat/ppp_net.c
@@ -80,7 +80,8 @@ static gboolean ppp_net_callback(GIOChannel *channel, GIOCondition cond,
 
 	if (cond & G_IO_IN) {
 		/* leave space to add PPP protocol field */
-		status = g_io_channel_read_chars(channel, buf + 2, MAX_PACKET,
+		status = g_io_channel_read_chars(channel,
+				buf + sizeof(struct ppp_header), MAX_PACKET,
 				&bytes_read, &error);
 		if (bytes_read > 0) {
 			ppp->proto = htons(PPP_IP_PROTO);
-- 
1.6.6.1



More information about the ofono mailing list