PPP LCP support

Implement LCP support for the PPP protocol.
This commit is contained in:
Kristen Carlson Accardi 2010-03-22 17:05:58 -07:00 committed by Marcel Holtmann
parent 31e99d9d78
commit cd5ddc2bee
5 changed files with 306 additions and 2 deletions

View File

@ -58,7 +58,7 @@ gatchat_sources = gatchat/gatchat.h gatchat/gatchat.c \
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

View File

@ -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 @@ void g_at_ppp_shutdown(GAtPPP *ppp)
/* 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 @@ GAtPPP *g_at_ppp_new(GIOChannel *modem)
ppp->index = 0;
/* initialize the lcp state */
ppp->lcp = lcp_new(ppp);
/* initialize the autentication state */

View File

@ -350,16 +350,19 @@ gboolean ppp_cb(GIOChannel *channel, GIOCondition cond, gpointer data)
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)
@ -452,3 +455,47 @@ 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);
}
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;
}

View File

@ -98,6 +98,7 @@ static inline guint16 __get_unaligned_short(const gpointer p)
struct _GAtPPP {
gint ref_count;
enum ppp_phase phase;
struct pppcp_data *lcp;
guint8 buffer[BUFFERSZ];
int index;
gint mru;
@ -130,3 +131,9 @@ 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);
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);

246
gatchat/ppp_lcp.c Normal file
View File

@ -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;
}