From fed838f79fe86eaeab7c28f45556f6e230568c58 Mon Sep 17 00:00:00 2001 From: Guillaume Zajac Date: Wed, 29 Jun 2011 10:20:24 +0200 Subject: GAtPPP: Add PFC option support --- gatchat/gatppp.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- gatchat/gatppp.h | 1 + gatchat/ppp.h | 4 ++++ gatchat/ppp_lcp.c | 35 ++++++++++++++++++++++++++++--- 4 files changed, 99 insertions(+), 4 deletions(-) (limited to 'gatchat') diff --git a/gatchat/gatppp.c b/gatchat/gatppp.c index 42b32246..919fd2f0 100644 --- a/gatchat/gatppp.c +++ b/gatchat/gatppp.c @@ -84,6 +84,7 @@ struct _GAtPPP { guint guard_timeout_source; gboolean suspended; gboolean xmit_acfc; + gboolean xmit_pfc; }; void ppp_debug(GAtPPP *ppp, const char *str) @@ -172,6 +173,7 @@ static void ppp_receive(const unsigned char *buf, gsize len, void *data) struct ppp_header *header = (struct ppp_header *) buf; gboolean acfc_frame = (header->address != PPP_ADDR_FIELD || header->control != PPP_CTRL); + gboolean pfc_frame = FALSE; guint16 protocol; const guint8 *packet; @@ -183,6 +185,20 @@ static void ppp_receive(const unsigned char *buf, gsize len, void *data) packet = ppp_info(buf); } + pfc_frame = (protocol != LCP_PROTOCOL && protocol != CHAP_PROTOCOL && + protocol != IPCP_PROTO && protocol != PPP_IP_PROTO); + + if (pfc_frame) { + guint8 proto = (protocol >> 8) & 0xFF ; + packet = packet - 1; + /* + * The only protocol that can be compressed is PPP_IP_PROTO + * because first byte is 0x00. + */ + if (proto == PPP_IP_COMPRESSED_PROTO) + protocol = PPP_IP_PROTO; + } + if (ppp_drop_packet(ppp, protocol)) return; @@ -264,6 +280,32 @@ static void ppp_send_acfc_frame(GAtPPP *ppp, guint8 *packet, if (ppp->xmit_acfc) offset = 2; + /* We remove the only address and control field */ + if (g_at_hdlc_send(ppp->hdlc, packet + offset, + infolen + sizeof(*header) - offset) + == FALSE) + DBG(ppp, "Failed to send a frame\n"); +} + +static void ppp_send_acfc_pfc_frame(GAtPPP *ppp, guint8 *packet, + guint infolen) +{ + struct ppp_header *header = (struct ppp_header *) packet; + guint offset = 0; + + if (ppp->xmit_acfc && ppp->xmit_pfc) + offset = 3; + else if (ppp->xmit_acfc) + offset = 2; + else if (ppp->xmit_pfc) { + /* + * We remove only the 1st byte that is 0x00 of protocol field. + */ + packet[2] = packet[1]; + packet[1] = packet[0]; + offset = 1; + } + if (g_at_hdlc_send(ppp->hdlc, packet + offset, infolen + sizeof(*header) - offset) == FALSE) @@ -285,9 +327,18 @@ void ppp_transmit(GAtPPP *ppp, guint8 *packet, guint infolen) break; case CHAP_PROTOCOL: case IPCP_PROTO: - case PPP_IP_PROTO: + /* + * We can't use PFC option because first byte of CHAP_PROTOCOL + * and IPCP_PROTO is not equal to 0x00 + */ ppp_send_acfc_frame(ppp, packet, infolen); break; + case PPP_IP_PROTO: + /* + * We can't use both compression options if they are negotiated + */ + ppp_send_acfc_pfc_frame(ppp, packet, infolen); + break; } } @@ -435,6 +486,11 @@ void ppp_set_xmit_acfc(GAtPPP *ppp, gboolean acfc) ppp->xmit_acfc = acfc; } +void ppp_set_xmit_pfc(GAtPPP *ppp, gboolean pfc) +{ + ppp->xmit_pfc = pfc; +} + static void io_disconnect(gpointer user_data) { GAtPPP *ppp = user_data; @@ -708,6 +764,11 @@ void g_at_ppp_set_acfc_enabled(GAtPPP *ppp, gboolean enabled) lcp_set_acfc_enabled(ppp->lcp, enabled); } +void g_at_ppp_set_pfc_enabled(GAtPPP *ppp, gboolean enabled) +{ + lcp_set_pfc_enabled(ppp->lcp, enabled); +} + static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip) { GAtPPP *ppp; diff --git a/gatchat/gatppp.h b/gatchat/gatppp.h index 1544b311..fcaf3a9d 100644 --- a/gatchat/gatppp.h +++ b/gatchat/gatppp.h @@ -80,6 +80,7 @@ void g_at_ppp_set_server_info(GAtPPP *ppp, const char *remote_ip, const char *dns1, const char *dns2); void g_at_ppp_set_acfc_enabled(GAtPPP *ppp, gboolean enabled); +void g_at_ppp_set_pfc_enabled(GAtPPP *ppp, gboolean enabled); #ifdef __cplusplus } diff --git a/gatchat/ppp.h b/gatchat/ppp.h index 41bcf7b0..414d2dfc 100644 --- a/gatchat/ppp.h +++ b/gatchat/ppp.h @@ -27,6 +27,8 @@ #define PPP_IP_PROTO 0x0021 #define MD5 5 +#define PPP_IP_COMPRESSED_PROTO 0x21 + #define DBG(p, fmt, arg...) do { \ char *str = g_strdup_printf("%s:%s() " fmt, __FILE__, \ __FUNCTION__ , ## arg); \ @@ -96,6 +98,7 @@ struct pppcp_data *lcp_new(GAtPPP *ppp, gboolean dormant); void lcp_free(struct pppcp_data *lcp); void lcp_protocol_reject(struct pppcp_data *lcp, guint8 *packet, gsize len); void lcp_set_acfc_enabled(struct pppcp_data *pppcp, gboolean enabled); +void lcp_set_pfc_enabled(struct pppcp_data *pppcp, gboolean enabled); /* IPCP related functions */ struct pppcp_data *ipcp_new(GAtPPP *ppp, gboolean is_server, guint32 ip); @@ -133,4 +136,5 @@ void ppp_set_recv_accm(GAtPPP *ppp, guint32 accm); void ppp_set_xmit_accm(GAtPPP *ppp, guint32 accm); void ppp_set_mtu(GAtPPP *ppp, const guint8 *data); void ppp_set_xmit_acfc(GAtPPP *ppp, gboolean acfc); +void ppp_set_xmit_pfc(GAtPPP *ppp, gboolean pfc); struct ppp_header *ppp_packet_new(gsize infolen, guint16 protocol); diff --git a/gatchat/ppp_lcp.c b/gatchat/ppp_lcp.c index c86a7d82..01b36bff 100644 --- a/gatchat/ppp_lcp.c +++ b/gatchat/ppp_lcp.c @@ -58,12 +58,13 @@ enum lcp_options { ACFC = 8, }; -/* Maximum size of all options, we only ever request ACCM, MRU and ACFC */ -#define MAX_CONFIG_OPTION_SIZE 12 +/* Maximum size of all options, we only ever request ACCM, MRU, ACFC and PFC */ +#define MAX_CONFIG_OPTION_SIZE 14 #define REQ_OPTION_ACCM 0x1 #define REQ_OPTION_MRU 0x2 #define REQ_OPTION_ACFC 0x4 +#define REQ_OPTION_PFC 0x8 struct lcp_data { guint8 options[MAX_CONFIG_OPTION_SIZE]; @@ -108,6 +109,13 @@ static void lcp_generate_config_options(struct lcp_data *lcp) len += 2; } + if (lcp->req_options & REQ_OPTION_PFC) { + lcp->options[len] = PFC; + lcp->options[len + 1] = 2; + + len += 2; + } + lcp->options_len = len; } @@ -293,9 +301,17 @@ static enum rcr_result lcp_rcr(struct pppcp_data *pppcp, ppp_set_mtu(ppp, ppp_option_iter_get_data(&iter)); break; case MAGIC_NUMBER: - case PFC: /* don't care */ break; + case PFC: + { + struct lcp_data *lcp = pppcp_get_data(pppcp); + + if (lcp->req_options & REQ_OPTION_PFC) + ppp_set_xmit_pfc(ppp, TRUE); + + break; + } case ACFC: { struct lcp_data *lcp = pppcp_get_data(pppcp); @@ -367,3 +383,16 @@ void lcp_set_acfc_enabled(struct pppcp_data *pppcp, gboolean enabled) lcp_generate_config_options(lcp); pppcp_set_local_options(pppcp, lcp->options, lcp->options_len); } + +void lcp_set_pfc_enabled(struct pppcp_data *pppcp, gboolean enabled) +{ + struct lcp_data *lcp = pppcp_get_data(pppcp); + + if (enabled == TRUE) + lcp->req_options |= REQ_OPTION_PFC; + else + lcp->req_options &= ~REQ_OPTION_PFC; + + lcp_generate_config_options(lcp); + pppcp_set_local_options(pppcp, lcp->options, lcp->options_len); +} -- cgit v1.2.3