---
 gatchat/gatppp.c  |   96 ++++++++++++++++++++++++++++++++++++++++-------------
 gatchat/gatppp.h  |    2 +
 gatchat/ppp.h     |    8 ++++
 gatchat/ppp_lcp.c |   31 +++++++++++++++--
 4 files changed, 110 insertions(+), 27 deletions(-)

diff --git a/gatchat/gatppp.c b/gatchat/gatppp.c
index 5fb4146..fe34ea1 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;
-
-               /*
-                * 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;
-       }
+       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 (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)
+{
+       lcp_turn_on_acfc(ppp->lcp);
+}
+
 static GAtPPP *ppp_init_common(gboolean is_server, guint32 ip)
 {
        GAtPPP *ppp;
diff --git a/gatchat/gatppp.h b/gatchat/gatppp.h
index f0930a7..428f08f 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);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/gatchat/ppp.h b/gatchat/ppp.h
index 023d779..9d118b0 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_turn_on_acfc(struct pppcp_data *pppcp);
 
 /* 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 ce9dae2..9dfd534 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,13 +101,19 @@ 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;
 }
 
 static void lcp_reset_config_options(struct lcp_data *lcp)
 {
        /* Using the default ACCM */
-
        lcp_generate_config_options(lcp);
 }
 
@@ -286,9 +293,15 @@ 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 +351,13 @@ struct pppcp_data *lcp_new(GAtPPP *ppp, gboolean is_server)
 
        return pppcp;
 }
+
+void lcp_turn_on_acfc(struct pppcp_data *pppcp)
+{
+       struct lcp_data *lcp = pppcp_get_data(pppcp);
+
+       lcp->req_options |= REQ_OPTION_ACFC;
+       lcp_generate_config_options(lcp);
+
+       pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
+}
-- 
1.7.1

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to