3 * PPP library with GLib integration
5 * Copyright (C) 2009-2011 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 #include <arpa/inet.h>
37 #define LCP_SUPPORTED_CODES ((1 << PPPCP_CODE_TYPE_CONFIGURE_REQUEST) | \
38 (1 << PPPCP_CODE_TYPE_CONFIGURE_ACK) | \
39 (1 << PPPCP_CODE_TYPE_CONFIGURE_NAK) | \
40 (1 << PPPCP_CODE_TYPE_CONFIGURE_REJECT) | \
41 (1 << PPPCP_CODE_TYPE_TERMINATE_REQUEST) | \
42 (1 << PPPCP_CODE_TYPE_TERMINATE_ACK) | \
43 (1 << PPPCP_CODE_TYPE_CODE_REJECT) | \
44 (1 << PPPCP_CODE_TYPE_PROTOCOL_REJECT) | \
45 (1 << PPPCP_CODE_TYPE_ECHO_REQUEST) | \
46 (1 << PPPCP_CODE_TYPE_ECHO_REPLY) | \
47 (1 << PPPCP_CODE_TYPE_DISCARD_REQUEST))
56 DEPRECATED_QUAL_PROTO = 6,
61 /* Maximum size of all options, we only ever request ACCM, MRU, ACFC and PFC */
62 #define MAX_CONFIG_OPTION_SIZE 14
64 #define REQ_OPTION_ACCM 0x1
65 #define REQ_OPTION_MRU 0x2
66 #define REQ_OPTION_ACFC 0x4
67 #define REQ_OPTION_PFC 0x8
70 guint8 options[MAX_CONFIG_OPTION_SIZE];
73 guint32 accm; /* ACCM value */
77 static void lcp_generate_config_options(struct lcp_data *lcp)
81 if (lcp->req_options & REQ_OPTION_ACCM) {
84 accm = htonl(lcp->accm);
86 lcp->options[len] = ACCM;
87 lcp->options[len + 1] = 6;
88 memcpy(lcp->options + len + 2, &accm, sizeof(accm));
93 if (lcp->req_options & REQ_OPTION_MRU) {
96 mru = htons(lcp->mru);
98 lcp->options[len] = MRU;
99 lcp->options[len + 1] = 4;
100 memcpy(lcp->options + len + 2, &mru, sizeof(mru));
105 if (lcp->req_options & REQ_OPTION_ACFC) {
106 lcp->options[len] = ACFC;
107 lcp->options[len + 1] = 2;
112 if (lcp->req_options & REQ_OPTION_PFC) {
113 lcp->options[len] = PFC;
114 lcp->options[len + 1] = 2;
119 lcp->options_len = len;
122 static void lcp_reset_config_options(struct lcp_data *lcp)
124 /* Using the default ACCM */
126 lcp_generate_config_options(lcp);
130 * signal the Up event to the NCP
132 static void lcp_up(struct pppcp_data *pppcp)
134 ppp_lcp_up_notify(pppcp_get_ppp(pppcp));
138 * signal the Down event to the NCP
140 static void lcp_down(struct pppcp_data *pppcp)
142 struct lcp_data *lcp = pppcp_get_data(pppcp);
144 lcp_reset_config_options(lcp);
145 pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
146 ppp_lcp_down_notify(pppcp_get_ppp(pppcp));
150 * Indicate that the lower layer is not needed
151 * Should trigger Down event
153 static void lcp_finished(struct pppcp_data *pppcp)
155 ppp_lcp_finished_notify(pppcp_get_ppp(pppcp));
158 static void lcp_rca(struct pppcp_data *pppcp, const struct pppcp_packet *packet)
160 struct ppp_option_iter iter;
162 ppp_option_iter_init(&iter, packet);
164 while (ppp_option_iter_next(&iter) == TRUE) {
165 const guint8 *data = ppp_option_iter_get_data(&iter);
166 switch (ppp_option_iter_get_type(&iter)) {
169 * RFC1662 Section 7.1
170 * The Configuration Option is used to inform the peer
171 * which control characters MUST remain mapped when
172 * the peer sends them.
175 ppp_set_recv_accm(pppcp_get_ppp(pppcp),
176 get_host_long(data));
184 static void lcp_rcn_nak(struct pppcp_data *pppcp,
185 const struct pppcp_packet *packet)
187 struct lcp_data *lcp = pppcp_get_data(pppcp);
188 struct ppp_option_iter iter;
190 ppp_option_iter_init(&iter, packet);
192 while (ppp_option_iter_next(&iter) == TRUE) {
193 const guint8 *data = ppp_option_iter_get_data(&iter);
195 switch (ppp_option_iter_get_type(&iter)) {
198 guint16 mru = get_host_short(data);
201 lcp->mru = get_host_short(data);
202 lcp->req_options |= REQ_OPTION_MRU;
212 lcp_generate_config_options(lcp);
213 pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
216 static void lcp_rcn_rej(struct pppcp_data *pppcp,
217 const struct pppcp_packet *packet)
222 static enum rcr_result lcp_rcr(struct pppcp_data *pppcp,
223 const struct pppcp_packet *packet,
224 guint8 **new_options, guint16 *new_len)
226 GAtPPP *ppp = pppcp_get_ppp(pppcp);
227 struct ppp_option_iter iter;
229 ppp_option_iter_init(&iter, packet);
231 while (ppp_option_iter_next(&iter) == TRUE) {
232 switch (ppp_option_iter_get_type(&iter)) {
235 const guint8 *option_data =
236 ppp_option_iter_get_data(&iter);
237 guint16 proto = get_host_short(option_data);
238 guint8 method = option_data[2];
241 switch (g_at_ppp_get_auth_method(ppp)) {
242 case G_AT_PPP_AUTH_METHOD_CHAP:
243 if (proto == CHAP_PROTOCOL && method == MD5)
247 * Try to suggest CHAP/MD5.
248 * Just reject if we run out of memory.
250 option = g_try_malloc0(5);
254 option[0] = AUTH_PROTO;
256 put_network_short(&option[2], CHAP_PROTOCOL);
258 *new_options = option;
263 case G_AT_PPP_AUTH_METHOD_PAP:
264 if (proto == PAP_PROTOCOL)
268 * Try to suggest PAP.
269 * Just reject if we run out of memory.
271 option = g_try_malloc0(4);
275 option[0] = AUTH_PROTO;
277 put_network_short(&option[2], PAP_PROTOCOL);
278 *new_options = option;
294 get_host_long(ppp_option_iter_get_data(&iter));
306 /* All options were found acceptable, apply them here and return */
307 ppp_option_iter_init(&iter, packet);
309 while (ppp_option_iter_next(&iter) == TRUE) {
310 switch (ppp_option_iter_get_type(&iter)) {
313 * RFC1662 Section 7.1
314 * The Configuration Option is used to inform the peer
315 * which control characters MUST remain mapped when
316 * the peer sends them.
318 ppp_set_xmit_accm(ppp,
319 get_host_long(ppp_option_iter_get_data(&iter)));
322 ppp_set_auth(ppp, ppp_option_iter_get_data(&iter));
325 ppp_set_mtu(ppp, ppp_option_iter_get_data(&iter));
332 struct lcp_data *lcp = pppcp_get_data(pppcp);
334 if (lcp->req_options & REQ_OPTION_PFC)
335 ppp_set_xmit_pfc(ppp, TRUE);
341 struct lcp_data *lcp = pppcp_get_data(pppcp);
343 if (lcp->req_options & REQ_OPTION_ACFC)
344 ppp_set_xmit_acfc(ppp, TRUE);
354 struct pppcp_proto lcp_proto = {
355 .proto = LCP_PROTOCOL,
357 .supported_codes = LCP_SUPPORTED_CODES,
358 .this_layer_up = lcp_up,
359 .this_layer_down = lcp_down,
360 .this_layer_finished = lcp_finished,
362 .rcn_nak = lcp_rcn_nak,
363 .rcn_rej = lcp_rcn_rej,
367 void lcp_free(struct pppcp_data *pppcp)
369 struct lcp_data *lcp = pppcp_get_data(pppcp);
375 struct pppcp_data *lcp_new(GAtPPP *ppp, gboolean is_server)
377 struct pppcp_data *pppcp;
378 struct lcp_data *lcp;
380 lcp = g_try_new0(struct lcp_data, 1);
384 pppcp = pppcp_new(ppp, &lcp_proto, is_server, 0);
390 pppcp_set_data(pppcp, lcp);
392 lcp_reset_config_options(lcp);
393 pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
398 void lcp_set_acfc_enabled(struct pppcp_data *pppcp, gboolean enabled)
400 struct lcp_data *lcp = pppcp_get_data(pppcp);
401 guint8 old = lcp->req_options;
404 lcp->req_options |= REQ_OPTION_ACFC;
406 lcp->req_options &= ~REQ_OPTION_ACFC;
408 if (lcp->req_options == old)
411 lcp_generate_config_options(lcp);
412 pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
415 void lcp_set_pfc_enabled(struct pppcp_data *pppcp, gboolean enabled)
417 struct lcp_data *lcp = pppcp_get_data(pppcp);
418 guint8 old = lcp->req_options;
421 lcp->req_options |= REQ_OPTION_PFC;
423 lcp->req_options &= ~REQ_OPTION_PFC;
425 if (lcp->req_options == old)
428 lcp_generate_config_options(lcp);
429 pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);