Skip to contentSkip to conversation

Add PPP protocol support with HDLC framing

PATCH In review [email protected] 3 participants 16 messages Mar 11, 2010 – Mar 17, 2010 1 message not in the archive Kbuild

lore
Share & tools
lore
#1 lore raw

PATCH 1/6 Add PPP protocol support with HDLC framing

In reply to a message not in the archive

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

Makefile.am +3 -1
Index: ofono/Makefile.am
===================================================================
@@ -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/gatppp_internal.h
 
 udev_files = plugins/ofono.rules
 
gatchat/gatppp_internal.h new file +97 -0

97 lines not on this page · raw message

gatchat/gatppp.c new file +557 -0

557 lines not on this page · raw message

gatchat/gatppp.h new file +81 -0

81 lines not on this page · raw message

#7 lore raw

PATCH 2/6 Generic PPP control protocol

In reply to a message not in the archive

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

Makefile.am +2 -1
Index: ofono/Makefile.am
===================================================================
@@ -57,7 +57,8 @@
 				gatchat/gat.h \
 				gatchat/gatserver.h gatchat/gatserver.c \
 				gatchat/gatppp.c gatchat/gatppp.h \
-				gatchat/gatppp_internal.h
+				gatchat/gatppp_internal.h gatchat/gatpppcp.c
+				gatchat/gatpppcp.h
 
 udev_files = plugins/ofono.rules
 
gatchat/gatpppcp.c new file +1492 -0

1,492 lines not on this page · raw message

gatchat/gatpppcp.h new file +133 -0

133 lines not on this page · raw message

gatchat/gatppp_internal.h +2 -0
Index: ofono/gatchat/gatppp_internal.h
===================================================================
@@ -26,6 +26,8 @@
 extern "C" {
 #endif
 
+#include "gatpppcp.h"
+
 #define DEFAULT_MRU	1500
 #define BUFFERSZ	DEFAULT_MRU*2
 #define DEFAULT_ACCM	0x00000000
#8 lore raw

PATCH 3/6 LCP support

In reply to a message not in the archive

Implement LCP support for the PPP protocol

Makefile.am +3 -3
Index: ofono/Makefile.am
===================================================================
@@ -56,9 +56,9 @@
 				gatchat/gatutil.h gatchat/gatutil.c \
 				gatchat/gat.h \
 				gatchat/gatserver.h gatchat/gatserver.c \
-				gatchat/gatppp.c gatchat/gatppp.h \
-				gatchat/gatppp_internal.h gatchat/gatpppcp.c
-				gatchat/gatpppcp.h
+				gatchat/gatppp_internal.h gatchat/gatpppcp.c \
+				gatchat/gatpppcp.h gatchat/gatppp.c \
+				gatchat/gatppplcp.c gatchat/gatppp.h
 
 udev_files = plugins/ofono.rules
 
gatchat/gatppp.c +52 -1

93 lines not on this page · raw message

gatchat/gatppp.h +1 -0
Index: ofono/gatchat/gatppp.h
===================================================================
@@ -43,6 +43,7 @@
 struct ppp_link {
 	gint ref_count;
 	guint phase;
+	struct pppcp_data *lcp;
 	guint8 *buffer;
 	int index;
 	gint mru;
gatchat/gatppp_internal.h +6 -0
Index: ofono/gatchat/gatppp_internal.h
===================================================================
@@ -91,6 +91,12 @@
 gboolean __ppp_get_pfc(struct ppp_link *link);
 void __ppp_set_acfc(struct ppp_link *link, gboolean acfc);
 gboolean __ppp_get_acfc(struct ppp_link *link);
+struct pppcp_data * lcp_new(struct ppp_link *link);
+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);
 #ifdef __cplusplus
 }
 #endif
gatchat/gatppplcp.c new file +225 -0

225 lines not on this page · raw message

#9 lore raw

PATCH 4/6 CHAP with MD5 authentication

In reply to a message not in the archive

Implement authentication support with CHAP and MD5 digest

Makefile.am +2 -1
Index: ofono/Makefile.am
===================================================================
@@ -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
 
gatchat/gatppp.c +13 -1
Index: ofono/gatchat/gatppp.c
===================================================================
@@ -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,
gatchat/gatppp.h +4 -0
Index: ofono/gatchat/gatppp.h
===================================================================
@@ -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
gatchat/gatppp_internal.h +14 -0
Index: ofono/gatchat/gatppp_internal.h
===================================================================
@@ -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
gatchat/gatpppauth.c new file +219 -0

219 lines not on this page · raw message

#10 lore raw

PATCH 5/6 IP support for PPP

In reply to a message not in the archive

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

Makefile.am +1 -1
Index: ofono/Makefile.am
===================================================================
@@ -59,7 +59,7 @@
 				gatchat/gatppp_internal.h gatchat/gatpppcp.c \
 				gatchat/gatpppcp.h gatchat/gatppp.c \
 				gatchat/gatppplcp.c gatchat/gatpppauth.c \
-				gatchat/gatppp.h
+				gatchat/gatpppnet.c gatchat/gatppp.h
 
 udev_files = plugins/ofono.rules
 
gatchat/gatppp_internal.h +11 -0
Index: ofono/gatchat/gatppp_internal.h
===================================================================
@@ -66,6 +66,13 @@
 	gpointer priv;
 };
 
+struct net_data {
+	struct ppp_link *link;
+	char *if_name;
+	GIOChannel *channel;
+	struct pppcp_data *ipcp;
+};
+
 struct auth_data {
 	guint16 proto;
 	gpointer proto_data;
@@ -111,6 +118,10 @@
 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);
+struct net_data *net_new(struct ppp_link *link);
+void net_open(struct net_data *data);
+void net_free(struct net_data *data);
+void net_close(struct net_data *data);
 #ifdef __cplusplus
 }
 #endif
gatchat/gatpppnet.c new file +355 -0

355 lines not on this page · raw message

gatchat/gatppp.h +2 -0
Index: ofono/gatchat/gatppp.h
===================================================================
@@ -28,6 +28,7 @@
 
 struct ppp_link;
 struct auth_data;
+struct net_data;
 
 enum PPP_CONNECT_STATUS {
 	PPP_CONNECT_SUCCESS,
@@ -46,6 +47,7 @@
 	guint phase;
 	struct pppcp_data *lcp;
 	struct auth_data *auth;
+	struct net_data *net;
 	guint8 *buffer;
 	int index;
 	gint mru;
#14 lore raw

PATCH 6/6 Allow gsmdial to use gatchat ppp support

In reply to a message not in the archive

Add option to use PPP to gsmdial.

gatchat/gsmdial.c +85 -2
Index: ofono/gatchat/gsmdial.c
===================================================================
@@ -33,6 +33,9 @@
 #include <glib.h>
 #include <gatchat.h>
 #include <gattty.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <gatppp.h>
 
 static const char *none_prefix[] = { NULL };
 static const char *cgreg_prefix[] = { "+CGREG:", NULL };
@@ -45,10 +48,14 @@
 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_passwd = NULL;
 
 static GAtChat *control;
 static GAtChat *modem;
 static GMainLoop *event_loop;
+static struct ppp_link *ppp;
 
 enum state {
 	STATE_NONE = 0,
@@ -220,6 +227,70 @@
 	g_at_chat_send(modem, buf, none_prefix, NULL, NULL, NULL);
 }
 
+static void print_ip_address(guint32 ip_addr)
+{
+	struct in_addr addr;
+	addr.s_addr = ip_addr;
+	g_print("%s\n", inet_ntoa(addr));
+}
+
+static void ppp_connect(struct ppp_link *link, gint success, guint32 ip_addr,
+		 guint32 dns1, guint32 dns2, gpointer user_data)
+{
+	if (success == PPP_CONNECT_SUCCESS) {
+		/* print out the negotiated address and dns server */
+		g_print("Negotiated IP Address: ");
+		print_ip_address(ip_addr);
+
+		g_print("Primary DNS Server: ");
+		print_ip_address(dns1);
+
+		g_print("Secondary DNS Server: ");
+		print_ip_address(dns2);
+	} else {
+		g_print("Failed to create PPP interface!\n");
+	}
+}
+
+static void ppp_disconnect(struct ppp_link *link, 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);
+	}
+
+	/* get the data IO channel */
+	channel = g_at_chat_get_channel(modem);
+	channel = g_io_channel_ref(channel);
+
+	/* shutdown gatchat */
+	g_at_chat_unref(control);
+	g_at_chat_unref(modem);
+
+	/* open ppp */
+	ppp = g_at_ppp_new(channel);
+	if (ppp) {
+		g_print("Setting PPP Credentials to %s, %s\n", option_username,
+				option_passwd);
+		g_at_ppp_set_credentials(ppp, option_username,
+					option_passwd);
+
+		/* 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];
@@ -231,8 +302,14 @@
 
 	if (option_legacy == TRUE) {
 			sprintf(buf, "ATD*99***%u#", option_cid);
-			g_at_chat_send(modem, buf, none_prefix,
-					NULL, NULL, NULL);
+			if (option_ppp == TRUE) {
+				g_print("Option PPP enabled\n");
+				g_at_chat_send(modem, buf, none_prefix,
+						connect_cb, NULL, NULL);
+			}
+			else
+				g_at_chat_send(modem, buf, none_prefix,
+						NULL, NULL, NULL);
 	} else {
 		sprintf(buf, "AT+CGACT=1,%u", option_cid);
 		g_at_chat_send(control, buf, none_prefix,
@@ -406,6 +483,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_passwd,
+				"Specifiy PPP Password" },
 	{ NULL },
 };
 
#2 lore raw
In reply to [email protected]

Hi Kristen,

Quoted 5 lines

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

Index: ofono/Makefile.am

===================================================================

Quoted 13 lines
Makefile.am +3 -1
@@ -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/gatppp_internal.h
 
 udev_files = plugins/ofono.rules
 
Quoted 2 lines

Index: ofono/gatchat/gatppp_internal.h

===================================================================

Quoted 61 lines
gatchat/gatppp_internal.h new file +57 -0
@@ -0,0 +1,97 @@
+/*
+ *
+ *  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 + *
+ */
+
+#ifndef __G_AT_PPP_INTERNAL_H
+#define __G_AT_PPP_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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 {
+	DEAD = 0,
+	ESTABLISHMENT,
+	AUTHENTICATION,
+	NETWORK,
+	TERMINATION,
+};
+
+enum PPP_EVENTS {
+	PPP_UP = 1,
+	PPP_OPENED,
+	PPP_SUCCESS,
+	PPP_NONE,
+	PPP_CLOSING,
+	PPP_FAIL,
+	PPP_DOWN

gatchat/gatppp_internal.h line 68

Quoted 10 lines
gatchat/gatppp_internal.h new file +10 -0
+};
+
+struct ppp_packet_handler {
+	guint16 proto;
+	void (*handler)(gpointer priv, guint8 *packet);
+	gpointer priv;
+};
+
+#define ppp_generate_event(l, e) \
+	__ppp_generate_event(l, e)

Why do we need this define?

gatchat/gatppp_internal.h line 72

Quoted 4 lines
gatchat/gatppp_internal.h new file +4 -0
+
+#define ppp_transmit(l, p, i) \
+	__ppp_transmit(l, p, i)
+

and this?

gatchat/gatppp_internal.h line 74

Quoted 2 lines
gatchat/gatppp_internal.h new file +2 -0
+#define ppp_register_packet_handler(h) \
+	__ppp_register_packet_handler(h)

or this?

Quoted 23 lines
gatchat/gatppp_internal.h new file +23 -0
+
+#define ppp_info(packet) \
+	(packet+4)
+
+#define ppp_proto(packet) \
+	(ntohs(*((guint16*)(packet+2))))
+
+void __ppp_generate_event(struct ppp_link *link, guint event);
+void __ppp_register_packet_handler(struct ppp_packet_handler *handler);
+void __ppp_transmit(struct ppp_link *link, guint8 *packet, guint infolen);
+void __ppp_set_auth(struct ppp_link *link, guint8 *auth_data);
+void __ppp_set_recv_accm(struct ppp_link *link, guint32 accm);
+guint32 __ppp_get_xmit_accm(struct ppp_link *link);
+void __ppp_set_pfc(struct ppp_link *link, gboolean pfc);
+gboolean __ppp_get_pfc(struct ppp_link *link);
+void __ppp_set_acfc(struct ppp_link *link, gboolean acfc);
+gboolean __ppp_get_acfc(struct ppp_link *link);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __G_AT_PPP_INTERNAL_H */
+
Quoted 2 lines

Index: ofono/gatchat/gatppp.c

===================================================================

Quoted 256 lines
gatchat/gatppp.c new file +252 -0
@@ -0,0 +1,557 @@
+/*
+ *
+ *  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"
+
+#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(struct ppp_link *link, guint8 c, gboolean lcp)
+{
+	if ((lcp && c < 0x20) || (link->xmit_accm[c >> 5] & (1 << (c & 0x1f))))
+		return TRUE;
+	return FALSE;
+}
+
+static void ppp_put(struct ppp_link *link, guint8 *buf, int *pos,
+			guint8 c, gboolean lcp)
+{
+	int i = *pos;
+
+	/* escape characters if needed,  copy into buf, increment pos */
+	if (ppp_escape(link, 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(struct ppp_link *link, guint8 *data, int len,
+				guint *newlen)
+{
+	guint8 *frame = g_malloc0(BUFFERSZ);
+	int pos = 0;
+	int i = 0;
+	guint16 fcs = PPPINITFCS16;
+	guint16 proto = ntohs(*(guint16 *)data);
+	gboolean lcp = (proto == LCP_PROTOCOL);
+	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(link, frame, &pos, PPP_ADDR_FIELD, lcp);
+	fcs = ppp_fcs(fcs, PPP_CTRL);
+	ppp_put(link, 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(link, frame, &pos, data[i++], lcp);
+	}
+
+	/* add FCS */
+	fcs ^= 0xffff;                 /* complement */
+	ppp_put(link, frame, &pos, (guint8)(fcs & 0x00ff), lcp);
+	ppp_put(link, frame, &pos, (guint8)((fcs >> 8) & 0x00ff), lcp);
+
+	/* add flag */
+	frame[pos++] = PPP_FLAG_SEQ;
+
+	*newlen = pos;
+	return frame;
+}
+
+static gint is_proto_handler(struct ppp_packet_handler *h, gpointer user)
+{
+	guint16 proto = (guint16) GPOINTER_TO_UINT(user);
+
+	if (h->proto == proto)
+		return 0;
+	else
+		return -1;
+}
+
+/* called when we have received a complete ppp frame */
+static void ppp_recv(struct ppp_link *link)
+{
+	guint16 protocol;
+	guint8 *frame, *packet;
+	GList *list;
+	struct ppp_packet_handler *h;
+
+	/* pop frames off of receive queue */
+	while ((frame = g_queue_pop_head(link->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),
+				(GCompareFunc) 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(struct ppp_link *link, guint8 *frame)
+{
+	guint8 *data;
+	guint pos = 0;
+	int i = 0;
+	int len;
+	guint16 fcs;
+
+	data = g_malloc0(link->mru + 10);
+
+	/* 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(struct ppp_link *link, guint8 *data, gsize len)
+{
+	guint pos = 0;
+	guint8 *frame;

gatchat/gatppp.c line 263

Quoted 10 lines
gatchat/gatppp.c new file +10 -0
+
+	/* 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 (link->buffer == NULL) {
+				link->buffer = g_malloc0(BUFFERSZ);
+				link->index = 0;

So my question is why do we keep allocating / freeing this buffer. Seems like a waste of time..?

gatchat/gatppp.c line 267

Quoted 4 lines
gatchat/gatppp.c new file +4 -0
+			} else {
+				/* store last flag character */
+				link->buffer[link->index++] = data[pos];
+				frame = ppp_decode(link, link->buffer);

This function along with ppp_decode do almost exactly the same thing as gsm0710_advanced_extract_frame in gsm0710.c. They both do HDLC frame decoding, and the only difference I can see is in the fcs table. Can we combine these somehow?

Quoted 5 lines
gatchat/gatppp.c new file +5 -0
+				/* push decoded frame onto receive queue */
+				if (frame)
+					g_queue_push_tail(link->recv_queue,
+								frame);
+

gatchat/gatppp.c line 282

Quoted 10 lines
gatchat/gatppp.c new file +10 -0
+				/* free and reintialize buffer */
+				g_free(link->buffer);
+				link->buffer = NULL;
+				link->index = 0;
+				continue;
+			}
+		}
+		/* copy byte to buffer */
+		if (link->buffer)
+			link->buffer[link->index++] = data[pos];

What concerns me here is that we don't check for buffer overflow here.

Quoted 30 lines
gatchat/gatppp.c new file +30 -0
+		else
+			g_printerr("oops, no buffer, no start of frame\n");
+
+	}
+	/* process receive queue */
+	ppp_recv(link);
+}
+
+/*
+ * transmit out through the lower layer interface
+ *
+ * infolen - length of the information part of the packet
+ */
+void __ppp_transmit(struct ppp_link *link, 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(link, packet, infolen+2, &framelen);
+	if (!frame) {
+		g_printerr("Failed to encode packet to transmit\n");
+		return;
+	}

gatchat/gatppp.c line 322

Quoted 10 lines
gatchat/gatppp.c new file +9 -0
+
+	/* 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(link->modem, (gchar *) frame,
+                                          framelen, &bytes_written,
 &error); +
+	g_free(frame);

You set the underlying IO channel to be non-blocking below. Strictly speaking what you have here will not work out, you cannot assume that the entire frame will be written.

You will need to add some sort of tx_queue and start a G_IO_OUT channel watch to handle this properly. However I'm fine fixing this later...

Quoted 180 lines
gatchat/gatppp.c new file +179 -0
+
+}
+
+static gboolean ppp_cb(GIOChannel *channel, GIOCondition cond, gpointer
 data) +{
+	struct ppp_link *ppp = (struct ppp_link *) 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 */
+static void ppp_close(struct ppp_link *link)
+{
+	/* send a CLOSE event to the lcp layer */
+}
+
+/* Administrative Open */
+void g_at_ppp_open(struct ppp_link *link)
+{
+	/* send an OPEN event to the lcp layer */
+}
+
+static void ppp_link_establishment(struct ppp_link *link)
+{
+	/* signal UP event to LCP */
+}
+
+static void ppp_terminate(struct ppp_link *link)
+{
+	/* signal DOWN event to LCP */
+}
+
+static void ppp_authenticate(struct ppp_link *link)
+{
+	/* we don't do authentication right now, so send NONE */
+	if (!link->auth_proto)
+		ppp_generate_event(link, PPP_NONE);
+	/* otherwise we need to wait for the peer to send us a challenge */
+}
+
+static void ppp_dead(struct ppp_link *link)
+{
+	/* re-initialize everything */
+}
+
+static void ppp_network(struct ppp_link *link)
+{
+	/* bring network phase up */
+}
+
+static void ppp_transition_phase(struct ppp_link *link, guint phase)
+{
+	/* don't do anything if we're already there */
+	if (link->phase == phase)
+		return;
+
+	/* set new phase */
+	link->phase = phase;
+
+	switch(phase) {
+	case ESTABLISHMENT:
+		ppp_link_establishment(link);
+		break;
+	case AUTHENTICATION:
+		ppp_authenticate(link);
+		break;
+	case TERMINATION:
+		ppp_terminate(link);
+		break;
+	case DEAD:
+		ppp_dead(link);
+		break;
+	case NETWORK:
+		ppp_network(link);
+		break;
+	default:
+		break;
+	}
+
+}
+
+static void ppp_handle_event(struct ppp_link *link)
+{
+	guint event;
+
+	while ((event = GPOINTER_TO_UINT(g_queue_pop_head(link->event_queue)))){
+		switch(event) {
+		case PPP_UP:
+			/* causes transition to link establishment */
+			ppp_transition_phase(link, ESTABLISHMENT);
+			break;
+		case PPP_OPENED:
+			ppp_transition_phase(link, AUTHENTICATION);
+			break;
+		case PPP_CLOSING:
+			/* causes transition to termination phase */
+			ppp_transition_phase(link, TERMINATION);
+			break;
+		case PPP_DOWN:
+			/* cases transition to dead phase */
+			ppp_transition_phase(link, DEAD);
+			break;
+		case PPP_NONE:
+		case PPP_SUCCESS:
+			/* causes transition to network phase */
+			ppp_transition_phase(link, NETWORK);
+			break;
+		}
+	}
+}
+
+/*
+ * send the event handler a new event to process
+ */
+void __ppp_generate_event(struct ppp_link *link, guint event)
+{
+	g_queue_push_tail(link->event_queue, GUINT_TO_POINTER(event));
+	ppp_handle_event(link);
+}
+
+void g_at_ppp_set_connect_function(struct ppp_link *link,
+			       GAtPPPConnectFunc callback, gpointer user_data)
+{
+	link->connect_cb = callback;
+	link->connect_priv = user_data;
+}
+
+void g_at_ppp_set_disconnect_function(struct ppp_link *link,
+				  GAtPPPDisconnectFunc callback,
+				  gpointer user_data)
+{
+	link->disconnect_cb = callback;
+	link->disconnect_priv = user_data;
+}
+
+void g_at_ppp_shutdown(struct ppp_link *link)
+{
+	/* close the link */
+	ppp_close(link);
+
+	/* clean up all the queues */
+	g_queue_free(link->event_queue);
+	g_queue_free(link->recv_queue);
+
+	/* cleanup modem channel */
+	g_source_remove(link->modem_watch);
+	g_io_channel_unref(link->modem);
+}
+
+void g_at_ppp_ref(struct ppp_link *link)
+{
+	g_atomic_int_inc(&link->ref_count);
+}
+
+void g_at_ppp_unref(struct ppp_link *link)
+{
+	gboolean last;
+
+	last = g_atomic_int_dec_and_test(&link->ref_count);
+	if (last) {
+		g_at_ppp_shutdown(link);
+		g_free(link);

gatchat/gatppp.c line 512

Quoted 10 lines
gatchat/gatppp.c new file +10 -0
+	}
+}
+
+struct ppp_link * g_at_ppp_new(GIOChannel *modem)
+{
+	struct ppp_link *link;
+	GIOFlags flags;
+	int signal_source;
+
+	link = g_malloc0(sizeof(struct ppp_link));

I suggest using g_try_new0 instead of g_malloc0

Quoted 18 lines
gatchat/gatppp.c new file +18 -0
+	if (!link)
+		return NULL;
+
+	link->ref_count = 1;
+
+	/* set options to defaults */
+	link->mru = DEFAULT_MRU;
+	link->recv_accm = DEFAULT_ACCM;
+	link->xmit_accm[0] = DEFAULT_ACCM;
+	link->xmit_accm[3] = 0x60000000; /* 0x7d, 0x7e */
+	link->pfc = FALSE;
+	link->acfc = FALSE;
+
+	/* allocate the queues */
+	link->event_queue = g_queue_new();
+	link->recv_queue = g_queue_new();
+
+	link->buffer = NULL;

gatchat/gatppp.c line 540

Quoted 10 lines
gatchat/gatppp.c new file +10 -0
+	link->index = 0;
+
+	/* setup the watch functions for the modem */
+	link->modem = g_io_channel_ref(modem);
+
+	flags = g_io_channel_get_flags(modem) | G_IO_FLAG_NONBLOCK;
+	g_io_channel_set_flags(modem, flags, NULL);
+
+	g_io_channel_set_encoding(modem, NULL, NULL);
+	g_io_channel_set_buffered(modem, FALSE);

g_at_util_setup_io does the above four operations for you. Might be a good idea to use that instead.

Quoted 4 lines
gatchat/gatppp.c new file +4 -0
+
+	/* initialize the lcp state */
+
+

gatchat/gatppp.c line 554

Quoted 10 lines
gatchat/gatppp.c new file +10 -0
+	/* initialize the autentication state */
+
+
+	/* intialize the network state */
+
+	/* start listening for packets from the modem */
+	signal_source = g_io_add_watch(modem,
+			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+			ppp_cb, link);
+	link->modem_watch = signal_source;

Shouldn't we assign this directly and avoid the signal_source variable altogether?

Quoted 5 lines
gatchat/gatppp.c new file +3 -0
+
+	return link;
+}

Index: ofono/gatchat/gatppp.h

===================================================================

Quoted 22 lines
gatchat/gatppp.h new file +18 -0
@@ -0,0 +1,81 @@
+/*
+ *
+ *  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 + *

gatchat/gatppp.h line 29

Quoted 10 lines
gatchat/gatppp.h new file +10 -0
+ */
+
+#ifndef __G_AT_PPP_H
+#define __G_AT_PPP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ppp_link;

For consistency this should be typedefed to GAtPpp, similar to how GAtChat is typedefed.

gatchat/gatppp.h line 35

Quoted 6 lines
gatchat/gatppp.h new file +6 -0
+
+enum PPP_CONNECT_STATUS {
+	PPP_CONNECT_SUCCESS,
+	PPP_CONNECT_FAIL
+};
+

The enum names should be prefixed by G_AT. e.g. G_AT_PPP_RESULT_OK, G_AT_PPP_RESULT_UNSPECIFIED_ERROR, G_AT_PPP_RESULT_AUTH_ERROR, etc. Keep the enum definition itself camel-case, e.g. enum _GAtPppResult, typedef to GAtPppResult

gatchat/gatppp.h line 39

Quoted 5 lines
gatchat/gatppp.h new file +4 -0
+typedef void (*GAtPPPConnectFunc)(struct ppp_link *link, gint success,
+				 guint32 ip_address,
+				 guint32 dns1, guint32 dns2,
+				 gpointer user_data);

I suggest that the gint success be changed to use the enum defined above.

gatchat/gatppp.h line 45

Quoted 6 lines
gatchat/gatppp.h new file +5 -0
+
+typedef void (*GAtPPPDisconnectFunc)(struct ppp_link *link, gpointer
 user_data); +
+struct ppp_link {
+	gint ref_count;
+	guint phase;

I suggest you use the enum directly here instead of the guint.

Quoted 5 lines
gatchat/gatppp.h new file +5 -0
+	guint8 *buffer;
+	int index;
+	gint mru;
+	guint16 auth_proto;
+	char user_name[256];

gatchat/gatppp.h line 60

Quoted 10 lines
gatchat/gatppp.h new file +10 -0
+	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_priv;

The suffix 'data' is preferred over 'priv'

gatchat/gatppp.h line 62

Quoted 2 lines
gatchat/gatppp.h new file +2 -0
+	GAtPPPDisconnectFunc disconnect_cb;
+	gpointer disconnect_priv;

As above

gatchat/gatppp.h line 65

Quoted 3 lines
gatchat/gatppp.h new file +3 -0
+	gint modem_watch;
+};
+

If possible, I would suggest that you hide the struct implementation in the .c file instead of exposing it here.

Quoted 7 lines
gatchat/gatppp.h new file +6 -0
+struct ppp_link * g_at_ppp_new(GIOChannel *modem);
+void g_at_ppp_open(struct ppp_link *link);
+void g_at_ppp_set_connect_function(struct ppp_link *link,
+			       GAtPPPConnectFunc callback, gpointer user_data);
+void g_at_ppp_set_disconnect_function(struct ppp_link *link,
+				  GAtPPPDisconnectFunc callback,

gatchat/gatppp.h line 81

Quoted 10 lines
gatchat/gatppp.h new file +10 -0
+				  gpointer user_data);
+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);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __G_AT_PPP_H */
+

Regards,
-Denis

#5 lore raw
In reply to [email protected]

Hi Kristen,

gatchat/gatppp.h line 75

Quoted 10 lines
gatchat/gatppp.h new file +10 -0
+struct ppp_link * g_at_ppp_new(GIOChannel *modem);
+void g_at_ppp_open(struct ppp_link *link);
+void g_at_ppp_set_connect_function(struct ppp_link *link,
+			       GAtPPPConnectFunc callback, gpointer user_data);
+void g_at_ppp_set_disconnect_function(struct ppp_link *link,
+				  GAtPPPDisconnectFunc callback,
+				  gpointer user_data);
+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);

Almost forgot, let us not use struct ppp_link here, but instead use GAtPpp *ppp as the parameter. Again, mostly for consistency with how glib / gatchat does this.

Regards,
-Denis

#6 lore raw

Hi Denis,

Quoted 6 lines
Quoted 6 lines
gatchat/gatppp.h new file +6 -0
+struct ppp_link * g_at_ppp_new(GIOChannel *modem);
+void g_at_ppp_open(struct ppp_link *link);
+void g_at_ppp_set_connect_function(struct ppp_link *link,
+			       GAtPPPConnectFunc callback, gpointer user_data);
+void g_at_ppp_set_disconnect_function(struct ppp_link *link,
+				  GAtPPPDisconnectFunc callback,
Quoted 8 lines

gatchat/gatppp.h line 75

Quoted 4 lines
gatchat/gatppp.h new file +4 -0
+				  gpointer user_data);
+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);

Almost forgot, let us not use struct ppp_link here, but instead use GAtPpp *ppp as the parameter. Again, mostly for consistency with how glib / gatchat does this.

I am actually okay with GAtPPP since it looks much nicer. True camel case is making it harder to read.

Regards

Marcel

#15 lore raw

Re: [patch 6/6] Allow gsmdial to use gatchat ppp support

In reply to [email protected]

Hi Kristen,

gatchat/gsmdial.c line 38

Quoted 13 lines

Add option to use PPP to gsmdial.

Index: ofono/gatchat/gsmdial.c
===================================================================

gatchat/gsmdial.c +3 -0
@@ -33,6 +33,9 @@
 #include <glib.h>
 #include <gatchat.h>
 #include <gattty.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <gatppp.h>

please put system includes before glib or internal includes.

gatchat/gsmdial.c line 53

Quoted 9 lines
gatchat/gsmdial.c +3 -0
 static const char *none_prefix[] = { NULL };
 static const char *cgreg_prefix[] = { "+CGREG:", NULL };
@@ -45,10 +48,14 @@
 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_passwd = NULL;

Just use option_password here. Shortening is not really useful in this case.

Quoted 8 lines
gatchat/gsmdial.c +1 -0
 static GAtChat *control;
 static GAtChat *modem;
 static GMainLoop *event_loop;
+static struct ppp_link *ppp;
 
 enum state {
 	STATE_NONE = 0,

gatchat/gsmdial.c line 234

Quoted 8 lines
gatchat/gsmdial.c +5 -0
@@ -220,6 +227,70 @@
 	g_at_chat_send(modem, buf, none_prefix, NULL, NULL, NULL);
 }
 
+static void print_ip_address(guint32 ip_addr)
+{
+	struct in_addr addr;
+	addr.s_addr = ip_addr;
+	g_print("%s\n", inet_ntoa(addr));

It is just fine to use printf() like everybody else. The g_print function is pretty much stupid idea from GLib. Same as gchar should not be used either.

The only case where g_print makes sense is in GLib based unit tests.

And personally I would do

static void print_ip_address(const char *label, guint32 addr) {
}

That way you can later on just call one function and don't have to manually print the label first.

Quoted 7 lines
gatchat/gsmdial.c +7 -0
+static void ppp_connect(struct ppp_link *link, gint success, guint32 ip_addr,
+		 guint32 dns1, guint32 dns2, gpointer user_data)
+{
+	if (success == PPP_CONNECT_SUCCESS) {
+		/* print out the negotiated address and dns server */
+		g_print("Negotiated IP Address: ");
+		print_ip_address(ip_addr);

gatchat/gsmdial.c line 253

Quoted 10 lines
gatchat/gsmdial.c +10 -0
+
+		g_print("Primary DNS Server: ");
+		print_ip_address(dns1);
+
+		g_print("Secondary DNS Server: ");
+		print_ip_address(dns2);
+	} else {
+		g_print("Failed to create PPP interface!\n");
+	}
+}

So personally I prefer the style more like this:

	if (success != PPP_CONNECT_SUCCESS) {
		printf(... err msg ...);
		return;
	}

	printf(... success ...)

It is a lot better to get the error cases out of your way first and then just focus on the success case. Instead of handling success and then btw. we have to take of the error case.

gatchat/gsmdial.c line 271

Quoted 12 lines
gatchat/gsmdial.c +12 -0
+static void connect_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+	GIOChannel *channel;
+
+	if (!ok) {
+		g_print("Unable to define context\n");
+		exit(1);
+	}
+
+	/* get the data IO channel */
+	channel = g_at_chat_get_channel(modem);
+	channel = g_io_channel_ref(channel);

What is this reference for? The g_at_ppp_new() should take a reference on that channel anyway.

gatchat/gsmdial.c line 275

Quoted 3 lines
gatchat/gsmdial.c +3 -0
+	/* shutdown gatchat */
+	g_at_chat_unref(control);
+	g_at_chat_unref(modem);

If you try to protect these, then I prefer that you call g_at_chat_shutdown() here first and not directly unref them.

We should be able to keep the chat object around even if PPP is running now.

Quoted 6 lines
gatchat/gsmdial.c +6 -0
+	/* open ppp */
+	ppp = g_at_ppp_new(channel);
+	if (ppp) {
+		g_print("Setting PPP Credentials to %s, %s\n", option_username,
+				option_passwd);
+		g_at_ppp_set_credentials(ppp, option_username,

gatchat/gsmdial.c line 292

Quoted 10 lines
gatchat/gsmdial.c +10 -0
+					option_passwd);
+
+		/* 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);
+	}
+}

This should be again done like this:

	if (!ppp) {
		printf(... err msg ..)
		return;
	}

	g_at_ppp_set_credentials ....
Quoted 7 lines
gatchat/gsmdial.c +0 -0
 static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
 {
 	char buf[64];
@@ -231,8 +302,14 @@
 
 	if (option_legacy == TRUE) {
 			sprintf(buf, "ATD*99***%u#", option_cid);

gatchat/gsmdial.c line 312

Quoted 10 lines
gatchat/gsmdial.c +8 -2
-			g_at_chat_send(modem, buf, none_prefix,
-					NULL, NULL, NULL);
+			if (option_ppp == TRUE) {
+				g_print("Option PPP enabled\n");
+				g_at_chat_send(modem, buf, none_prefix,
+						connect_cb, NULL, NULL);
+			}
+			else
+				g_at_chat_send(modem, buf, none_prefix,
+						NULL, NULL, NULL);

I don't like this at all. Lets move the option_ppp check into the connect_cb function. Check for option_ppp in the callback and if not set, then leave the callback.

gatchat/gsmdial.c line 491

Quoted 13 lines
gatchat/gsmdial.c +6 -0
 	} else {
 		sprintf(buf, "AT+CGACT=1,%u", option_cid);
 		g_at_chat_send(control, buf, none_prefix,
@@ -406,6 +483,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_passwd,
+				"Specifiy PPP Password" },

Small nitpick. Username and Password should be both lowercase.

Regards

Marcel

#11 lore raw

Re: [patch 5/6] IP support for PPP

In reply to [email protected]

Hi Kristen,

Quoted 1 line

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

this is not a proper review of the patch, just some general comments I found by looking through the whole series.

Quoted 18 lines

===================================================================

gatchat/gatppp_internal.h +7 -0
@@ -66,6 +66,13 @@
 	gpointer priv;
 };
 
+struct net_data {
+	struct ppp_link *link;
+	char *if_name;
+	GIOChannel *channel;
+	struct pppcp_data *ipcp;
+};
+
 struct auth_data {
 	guint16 proto;
 	gpointer proto_data;

gatchat/gatppp_internal.h line 127

Quoted 10 lines
gatchat/gatppp_internal.h +4 -0
@@ -111,6 +118,10 @@
 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);
+struct net_data *net_new(struct ppp_link *link);
+void net_open(struct net_data *data);
+void net_free(struct net_data *data);
+void net_close(struct net_data *data);
 #ifdef __cplusplus
 }
 #endif

If these are not public exported header files, then I don't want the cplusplus or or circular inclusion protection ifdefs. I want developers fall flat on their face if they try to do something stupid.

So first we will never compiler internal header files with C++ so that is just pointless. They are internal and we will compile them with C compiler.

For the circular inclusion protection, I want the compiler to complain. Quite frankly if you need that for internal header files to make your code work. You code is way too complex. I want the compiler to tell us.

gatchat/gatppp_internal.h

Quoted 3 lines
gatchat/gatppp_internal.h +3 -0
+static void ip_process_packet(gpointer priv, guint8 *packet)
+{
+	struct net_data *data = (struct net_data *)priv;

This assignment should not be needed. It is a void pointer and can be assigned without casting.

As a general rule. Avoid casting as much as possible. Especially for void pointer and function pointers. I want the compiler to do sanity checks for us. Once you cast, all this extra protection is gone.

There is a reason for using -Wall -Wextra and -Werror and being pretty much pedantic about it. Developers should use ./bootstrap-configure since it enables all of these and more.

gatchat/gatppp_internal.h

Quoted 4 lines
gatchat/gatppp_internal.h +4 -0
+	GError *error = NULL;
+        GIOStatus status;
+        gsize bytes_written;
+	guint16 len;

Please use an editor that can visualize whitespaces vs tabs.

gatchat/gatppp_internal.h

Quoted 8 lines
gatchat/gatppp_internal.h +8 -0
+struct net_data *net_new(struct ppp_link *link)
+{
+	struct net_data *data;
+
+	data = g_malloc0(sizeof(*data));
+	if (data) {
+		data->link = link;
+		data->ipcp = ipcp_new(link);

So here is the tricky part with GLib memory allocations. The default function will abort when OOM case happens. What you really wanted here is actually g_try_malloc0.

And then again, please do it like this:

	data = g_try_malloc0(...)
	if (!data)
		return NULL;

	data->link = ...
Quoted 10 lines
gatchat/gatppp_internal.h +10 -0
+/****** IPCP support ****************/
+enum {
+	/* supported codes */
+	IPCP_SUPPORTED_CODES	= (1 << CONFIGURE_REQUEST) |
+				  (1 << CONFIGURE_ACK) |
+				  (1 << CONFIGURE_NAK) |
+				  (1 << CONFIGURE_REJECT) |
+				  (1 << TERMINATE_REQUEST) |
+				  (1 << TERMINATE_ACK) |
+				  (1 << CODE_REJECT),

gatchat/gatppp_internal.h

Quoted 10 lines
gatchat/gatppp_internal.h +10 -0
+
+	IPCP_PROTO		= 0x8021,
+
+	/* option types */
+	IP_ADDRESSES		= 1,
+	IP_COMPRESSION_PROTO	= 2,
+	IP_ADDRESS		= 3,
+	PRIMARY_DNS_SERVER	= 129,
+	SECONDARY_DNS_SERVER	= 131,
+};

I don't think enum is the right way for this. I can see it for the option types, but for IPCP_PROTO and IPCP_SUPPORTED_CODES. I would say just using simple defines is way better.

Feel free to convince me other way or show me what I have missed here.

gatchat/gatppp_internal.h

Quoted 5 lines
gatchat/gatppp_internal.h +5 -0
+static guint32 bytes_to_32(guint8 *bytes)
+{
+	return (bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) |
+			(bytes[3] << 24));
+}

Shouldn't this be done by an endian aware function that can also handle the unaligned case. I mentioned this before, on a non-x86 platform we need to worry about the alignment if you just access the memory location directly.

GLib should have proper functions for this. Just install the GLib documentation package and devhelp program. That way can easily search through it. Even when you are offline.

gatchat/gatppp.h line 31

Quoted 8 lines

===================================================================

gatchat/gatppp.h +1 -0
@@ -28,6 +28,7 @@
 
 struct ppp_link;
 struct auth_data;
+struct net_data;

Denis and I mentioned it already, please keep proper namespacing for public functions or structures in mind. It is really important.

Also here it might be not needed to expose them at all.

Regards

Marcel

#3 lore raw
In reply to Denis Kenzior
Quoted 10 lines · On Thu, 11 Mar 2010 20:17:49 -0600 Denis Kenzior <[email protected]> wrote:

gatchat/gatppp.c line 267

Quoted 5 lines
gatchat/gatppp.c new file +4 -0
+			} else {
+				/* store last flag character */
+				link->buffer[link->index++] = data[pos];
+				frame = ppp_decode(link, link->buffer);

This function along with ppp_decode do almost exactly the same thing as gsm0710_advanced_extract_frame in gsm0710.c. They both do HDLC frame decoding, and the only difference I can see is in the fcs table. Can we combine these somehow?

Possibly - although in theory in addition to the escaping that you do in the gsm0710 code, we have to support a negotiated accm (which you see I've not yet implemented here). We also in theory should support PFC and ACFC (which the one modem I tested with required, otherwise it refused to ack my Configure-Request). I think there may eventually be enough differences to keep these separate.

#4 lore raw

Hi Kristen,

Quoted 13 lines

On Thu, 11 Mar 2010 20:17:49 -0600

Quoted 9 lines · Denis Kenzior

gatchat/gatppp.c line 267

Quoted 4 lines
gatchat/gatppp.c new file +4 -0
+			} else {
+				/* store last flag character */
+				link->buffer[link->index++] = data[pos];
+				frame = ppp_decode(link, link->buffer);

This function along with ppp_decode do almost exactly the same thing as gsm0710_advanced_extract_frame in gsm0710.c. They both do HDLC frame decoding, and the only difference I can see is in the fcs table. Can we combine these somehow?

Quoted 7 lines

Possibly - although in theory in addition to the escaping that you do in the gsm0710 code, we have to support a negotiated accm (which you see I've not yet implemented here). We also in theory should support PFC and ACFC (which the one modem I tested with required, otherwise it refused to ack my Configure-Request). I think there may eventually be enough differences to keep these separate.

You will have to explain to me what that all means ;) However, it would be ideal if we can create a set of utilities that can be shared between ppp and mux code (maybe with extra configuration parameters turning on/off or passing in parameters required for pfc/acfc/accm support.)

No sense writing, testing and debugging (and more importantly maintaining) the same code twice.

Regards,
-Denis

#12 lore raw

Re: [patch 5/6] IP support for PPP

In reply to Marcel Holtmann
Quoted 25 lines · On Sun, 14 Mar 2010 13:22:37 -0700 Marcel Holtmann <[email protected]> wrote:
Quoted 10 lines
gatchat/gatpppnet.c new file +10 -0
+/****** IPCP support ****************/
+enum {
+	/* supported codes */
+	IPCP_SUPPORTED_CODES	= (1 << CONFIGURE_REQUEST) |
+				  (1 << CONFIGURE_ACK) |
+				  (1 << CONFIGURE_NAK) |
+				  (1 << CONFIGURE_REJECT) |
+				  (1 << TERMINATE_REQUEST) |
+				  (1 << TERMINATE_ACK) |
+				  (1 << CODE_REJECT),

gatchat/gatpppnet.c line 214

Quoted 10 lines
gatchat/gatpppnet.c new file +10 -0
+
+	IPCP_PROTO		= 0x8021,
+
+	/* option types */
+	IP_ADDRESSES		= 1,
+	IP_COMPRESSION_PROTO	= 2,
+	IP_ADDRESS		= 3,
+	PRIMARY_DNS_SERVER	= 129,
+	SECONDARY_DNS_SERVER	= 131,
+};

I don't think enum is the right way for this. I can see it for the option types, but for IPCP_PROTO and IPCP_SUPPORTED_CODES. I would say just using simple defines is way better.

Quoted 1 line

Feel free to convince me other way or show me what I have missed here.

It's mostly just a habit, but in general there are advantages to using enum vs. a define. You are assured that the scope is kept local, even if you are uncreative with your name choices, whereas with a macro it is not. Also it's sometimes easier to debug with an enum vs. a macro. I can certainly change it if you really want me too.

#16 lore raw

Re: [patch 6/6] Allow gsmdial to use gatchat ppp support

In reply to Marcel Holtmann
Quoted 11 lines · On Sun, 14 Mar 2010 13:02:52 -0700 Marcel Holtmann <[email protected]> wrote:

gatchat/gsmdial.c line 234

Quoted 6 lines
gatchat/gsmdial.c +5 -0
+static void print_ip_address(guint32 ip_addr)
+{
+	struct in_addr addr;
+	addr.s_addr = ip_addr;
+	g_print("%s\n", inet_ntoa(addr));

It is just fine to use printf() like everybody else. The g_print function is pretty much stupid idea from GLib. Same as gchar should not be used either.

Quoted 1 line

The only case where g_print makes sense is in GLib based unit tests.

OK, but I think I should leave this the way it is just because it is consistent with the rest of gsmdial.

#13 lore raw

Re: [patch 5/6] IP support for PPP

In reply to Kristen Carlson Accardi

Hi Kristen,

Quoted 25 lines
Quoted 25 lines
Quoted 10 lines
gatchat/gatpppnet.c new file +10 -0
+/****** IPCP support ****************/
+enum {
+	/* supported codes */
+	IPCP_SUPPORTED_CODES	= (1 << CONFIGURE_REQUEST) |
+				  (1 << CONFIGURE_ACK) |
+				  (1 << CONFIGURE_NAK) |
+				  (1 << CONFIGURE_REJECT) |
+				  (1 << TERMINATE_REQUEST) |
+				  (1 << TERMINATE_ACK) |
+				  (1 << CODE_REJECT),

gatchat/gatpppnet.c line 214

Quoted 10 lines
gatchat/gatpppnet.c new file +10 -0
+
+	IPCP_PROTO		= 0x8021,
+
+	/* option types */
+	IP_ADDRESSES		= 1,
+	IP_COMPRESSION_PROTO	= 2,
+	IP_ADDRESS		= 3,
+	PRIMARY_DNS_SERVER	= 129,
+	SECONDARY_DNS_SERVER	= 131,
+};

I don't think enum is the right way for this. I can see it for the option types, but for IPCP_PROTO and IPCP_SUPPORTED_CODES. I would say just using simple defines is way better.

Quoted 7 lines
Quoted 1 line

Feel free to convince me other way or show me what I have missed here.

It's mostly just a habit, but in general there are advantages to using enum vs. a define. You are assured that the scope is kept local, even if you are uncreative with your name choices, whereas with a macro it is not. Also it's sometimes easier to debug with an enum vs. a macro. I can certainly change it if you really want me too.

I have nothing against enums. I actually like them a lot if used correctly, because gcc and gdb does make your life easier.

The thing that I dislike is clashing namespaces and scopes in just one enum. In the example of both you mix two or more things that should at least in different enums.

Regards

Marcel