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 if ((proto == CHAP_PROTOCOL) && (method == MD5))
245 * try to suggest CHAP & MD5. If we are out
246 * of memory, just reject.
249 option = g_try_malloc0(5);
253 option[0] = AUTH_PROTO;
255 put_network_short(&option[2], CHAP_PROTOCOL);
257 *new_options = option;
270 get_host_long(ppp_option_iter_get_data(&iter));
282 /* All options were found acceptable, apply them here and return */
283 ppp_option_iter_init(&iter, packet);
285 while (ppp_option_iter_next(&iter) == TRUE) {
286 switch (ppp_option_iter_get_type(&iter)) {
289 * RFC1662 Section 7.1
290 * The Configuration Option is used to inform the peer
291 * which control characters MUST remain mapped when
292 * the peer sends them.
294 ppp_set_xmit_accm(ppp,
295 get_host_long(ppp_option_iter_get_data(&iter)));
298 ppp_set_auth(ppp, ppp_option_iter_get_data(&iter));
301 ppp_set_mtu(ppp, ppp_option_iter_get_data(&iter));
308 struct lcp_data *lcp = pppcp_get_data(pppcp);
310 if (lcp->req_options & REQ_OPTION_PFC)
311 ppp_set_xmit_pfc(ppp, TRUE);
317 struct lcp_data *lcp = pppcp_get_data(pppcp);
319 if (lcp->req_options & REQ_OPTION_ACFC)
320 ppp_set_xmit_acfc(ppp, TRUE);
330 struct pppcp_proto lcp_proto = {
331 .proto = LCP_PROTOCOL,
333 .supported_codes = LCP_SUPPORTED_CODES,
334 .this_layer_up = lcp_up,
335 .this_layer_down = lcp_down,
336 .this_layer_finished = lcp_finished,
338 .rcn_nak = lcp_rcn_nak,
339 .rcn_rej = lcp_rcn_rej,
343 void lcp_free(struct pppcp_data *pppcp)
345 struct lcp_data *lcp = pppcp_get_data(pppcp);
351 struct pppcp_data *lcp_new(GAtPPP *ppp, gboolean is_server)
353 struct pppcp_data *pppcp;
354 struct lcp_data *lcp;
356 lcp = g_try_new0(struct lcp_data, 1);
360 pppcp = pppcp_new(ppp, &lcp_proto, is_server, 0);
366 pppcp_set_data(pppcp, lcp);
368 lcp_reset_config_options(lcp);
369 pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
374 void lcp_set_acfc_enabled(struct pppcp_data *pppcp, gboolean enabled)
376 struct lcp_data *lcp = pppcp_get_data(pppcp);
377 guint8 old = lcp->req_options;
380 lcp->req_options |= REQ_OPTION_ACFC;
382 lcp->req_options &= ~REQ_OPTION_ACFC;
384 if (lcp->req_options == old)
387 lcp_generate_config_options(lcp);
388 pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
391 void lcp_set_pfc_enabled(struct pppcp_data *pppcp, gboolean enabled)
393 struct lcp_data *lcp = pppcp_get_data(pppcp);
394 guint8 old = lcp->req_options;
397 lcp->req_options |= REQ_OPTION_PFC;
399 lcp->req_options &= ~REQ_OPTION_PFC;
401 if (lcp->req_options == old)
404 lcp_generate_config_options(lcp);
405 pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);