From 84ccc874dad70dfa4464ae5a1b295373211882ca Mon Sep 17 00:00:00 2001 From: Guillaume Zajac Date: Wed, 29 Jun 2011 10:20:23 +0200 Subject: [PATCH] GAtPPP: Add ACFC option support --- gatchat/gatppp.c | 94 ++++++++++++++++++++++++++++++++++++----------- gatchat/gatppp.h | 2 + gatchat/ppp.h | 8 ++++ gatchat/ppp_lcp.c | 35 ++++++++++++++++-- 4 files changed, 114 insertions(+), 25 deletions(-) diff --git a/gatchat/gatppp.c b/gatchat/gatppp.c index 5fb41461..42b32246 100644 --- a/gatchat/gatppp.c +++ b/gatchat/gatppp.c @@ -83,6 +83,7 @@ struct _GAtPPP { int fd; guint guard_timeout_source; gboolean suspended; + gboolean xmit_acfc; }; void ppp_debug(GAtPPP *ppp, const char *str) @@ -168,8 +169,19 @@ static inline gboolean ppp_drop_packet(GAtPPP *ppp, guint16 protocol) static void ppp_receive(const unsigned char *buf, gsize len, void *data) { GAtPPP *ppp = data; - guint16 protocol = ppp_proto(buf); - const guint8 *packet = ppp_info(buf); + struct ppp_header *header = (struct ppp_header *) buf; + gboolean acfc_frame = (header->address != PPP_ADDR_FIELD + || header->control != PPP_CTRL); + guint16 protocol; + const guint8 *packet; + + if (acfc_frame) { + protocol = ppp_acfc_proto(buf); + packet = ppp_acfc_info(buf); + } else { + protocol = ppp_proto(buf); + packet = ppp_info(buf); + } if (ppp_drop_packet(ppp, protocol)) return; @@ -196,37 +208,29 @@ static void ppp_receive(const unsigned char *buf, gsize len, void *data) }; } -/* - * 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) +static void ppp_send_lcp_frame(GAtPPP *ppp, guint8 *packet, guint infolen) { struct ppp_header *header = (struct ppp_header *) packet; - guint16 proto = ppp_proto(packet); guint8 code; - gboolean lcp = (proto == LCP_PROTOCOL); guint32 xmit_accm = 0; gboolean sta = FALSE; + gboolean lcp; /* * all LCP Link Configuration, Link Termination, and Code-Reject * packets must be sent with the default sending ACCM */ - if (lcp) { - code = pppcp_get_code(packet); - lcp = code > 0 && code < 8; + code = pppcp_get_code(packet); + lcp = code > 0 && code < 8; - /* - * If we're going down, we try to make sure to send the final - * ack before informing the upper layers via the ppp_disconnect - * function. Once we enter PPP_DEAD phase, no further packets - * will be sent - */ - if (code == PPPCP_CODE_TYPE_TERMINATE_ACK) - sta = TRUE; - } + /* + * If we're going down, we try to make sure to send the final + * ack before informing the upper layers via the ppp_disconnect + * function. Once we enter PPP_DEAD phase, no further packets + * will be sent + */ + if (code == PPPCP_CODE_TYPE_TERMINATE_ACK) + sta = TRUE; if (lcp) { xmit_accm = g_at_hdlc_get_xmit_accm(ppp->hdlc); @@ -251,6 +255,42 @@ void ppp_transmit(GAtPPP *ppp, guint8 *packet, guint infolen) g_at_hdlc_set_xmit_accm(ppp->hdlc, xmit_accm); } +static void ppp_send_acfc_frame(GAtPPP *ppp, guint8 *packet, + guint infolen) +{ + struct ppp_header *header = (struct ppp_header *) packet; + guint offset = 0; + + if (ppp->xmit_acfc) + offset = 2; + + if (g_at_hdlc_send(ppp->hdlc, packet + offset, + infolen + sizeof(*header) - offset) + == FALSE) + DBG(ppp, "Failed to send a frame\n"); +} + +/* + * 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) +{ + guint16 proto = ppp_proto(packet); + + switch (proto) { + case LCP_PROTOCOL: + ppp_send_lcp_frame(ppp, packet, infolen); + break; + case CHAP_PROTOCOL: + case IPCP_PROTO: + case PPP_IP_PROTO: + ppp_send_acfc_frame(ppp, packet, infolen); + break; + } +} + static inline void ppp_enter_phase(GAtPPP *ppp, enum ppp_phase phase) { DBG(ppp, "%d", phase); @@ -390,6 +430,11 @@ void ppp_set_mtu(GAtPPP *ppp, const guint8 *data) ppp->mtu = mtu; } +void ppp_set_xmit_acfc(GAtPPP *ppp, gboolean acfc) +{ + ppp->xmit_acfc = acfc; +} + static void io_disconnect(gpointer user_data) { GAtPPP *ppp = user_data; @@ -658,6 +703,11 @@ void g_at_ppp_set_server_info(GAtPPP *ppp, const char *remote, ipcp_set_server_info(ppp->ipcp, r, d1, d2); } +void g_at_ppp_set_acfc_enabled(GAtPPP *ppp, gboolean enabled) +{ + lcp_set_acfc_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 f0930a77..1544b311 100644 --- a/gatchat/gatppp.h +++ b/gatchat/gatppp.h @@ -79,6 +79,8 @@ void g_at_ppp_set_recording(GAtPPP *ppp, const char *filename); 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); + #ifdef __cplusplus } #endif diff --git a/gatchat/ppp.h b/gatchat/ppp.h index 023d779a..41bcf7b0 100644 --- a/gatchat/ppp.h +++ b/gatchat/ppp.h @@ -85,10 +85,17 @@ static inline void __put_unaligned_short(void *p, guint16 val) #define ppp_proto(packet) \ (get_host_short(packet + 2)) +#define ppp_acfc_info(packet) \ + (packet + 2) + +#define ppp_acfc_proto(packet) \ + (get_host_short(packet)) + /* LCP related functions */ 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); /* IPCP related functions */ struct pppcp_data *ipcp_new(GAtPPP *ppp, gboolean is_server, guint32 ip); @@ -125,4 +132,5 @@ void ppp_lcp_finished_notify(GAtPPP *ppp); 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); struct ppp_header *ppp_packet_new(gsize infolen, guint16 protocol); diff --git a/gatchat/ppp_lcp.c b/gatchat/ppp_lcp.c index ce9dae29..c86a7d82 100644 --- a/gatchat/ppp_lcp.c +++ b/gatchat/ppp_lcp.c @@ -58,11 +58,12 @@ enum lcp_options { ACFC = 8, }; -/* Maximum size of all options, we only ever request ACCM and MRU */ -#define MAX_CONFIG_OPTION_SIZE 10 +/* Maximum size of all options, we only ever request ACCM, MRU and ACFC */ +#define MAX_CONFIG_OPTION_SIZE 12 #define REQ_OPTION_ACCM 0x1 #define REQ_OPTION_MRU 0x2 +#define REQ_OPTION_ACFC 0x4 struct lcp_data { guint8 options[MAX_CONFIG_OPTION_SIZE]; @@ -100,6 +101,13 @@ static void lcp_generate_config_options(struct lcp_data *lcp) len += 4; } + if (lcp->req_options & REQ_OPTION_ACFC) { + lcp->options[len] = ACFC; + lcp->options[len + 1] = 2; + + len += 2; + } + lcp->options_len = len; } @@ -286,9 +294,17 @@ static enum rcr_result lcp_rcr(struct pppcp_data *pppcp, break; case MAGIC_NUMBER: case PFC: - case ACFC: /* don't care */ break; + case ACFC: + { + struct lcp_data *lcp = pppcp_get_data(pppcp); + + if (lcp->req_options & REQ_OPTION_ACFC) + ppp_set_xmit_acfc(ppp, TRUE); + + break; + } } } @@ -338,3 +354,16 @@ struct pppcp_data *lcp_new(GAtPPP *ppp, gboolean is_server) return pppcp; } + +void lcp_set_acfc_enabled(struct pppcp_data *pppcp, gboolean enabled) +{ + struct lcp_data *lcp = pppcp_get_data(pppcp); + + if (enabled == TRUE) + lcp->req_options |= REQ_OPTION_ACFC; + else + lcp->req_options &= ~REQ_OPTION_ACFC; + + lcp_generate_config_options(lcp); + pppcp_set_local_options(pppcp, lcp->options, lcp->options_len); +}