Upgrade ofono to 1.2
[profile/ivi/ofono.git] / gatchat / ppp_lcp.c
1 /*
2  *
3  *  PPP library with GLib integration
4  *
5  *  Copyright (C) 2009-2011  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <termios.h>
31 #include <glib.h>
32 #include <arpa/inet.h>
33
34 #include "gatppp.h"
35 #include "ppp.h"
36
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))
48
49 enum lcp_options {
50         RESERVED                = 0,
51         MRU                     = 1,
52         ACCM                    = 2,
53         AUTH_PROTO              = 3,
54         QUAL_PROTO              = 4,
55         MAGIC_NUMBER            = 5,
56         DEPRECATED_QUAL_PROTO   = 6,
57         PFC                     = 7,
58         ACFC                    = 8,
59 };
60
61 /* Maximum size of all options, we only ever request ACCM, MRU, ACFC and PFC */
62 #define MAX_CONFIG_OPTION_SIZE 14
63
64 #define REQ_OPTION_ACCM 0x1
65 #define REQ_OPTION_MRU  0x2
66 #define REQ_OPTION_ACFC 0x4
67 #define REQ_OPTION_PFC  0x8
68
69 struct lcp_data {
70         guint8 options[MAX_CONFIG_OPTION_SIZE];
71         guint16 options_len;
72         guint8 req_options;
73         guint32 accm;                   /* ACCM value */
74         guint16 mru;
75 };
76
77 static void lcp_generate_config_options(struct lcp_data *lcp)
78 {
79         guint16 len = 0;
80
81         if (lcp->req_options & REQ_OPTION_ACCM) {
82                 guint32 accm;
83
84                 accm = htonl(lcp->accm);
85
86                 lcp->options[len] = ACCM;
87                 lcp->options[len + 1] = 6;
88                 memcpy(lcp->options + len + 2, &accm, sizeof(accm));
89
90                 len += 6;
91         }
92
93         if (lcp->req_options & REQ_OPTION_MRU) {
94                 guint16 mru;
95
96                 mru = htons(lcp->mru);
97
98                 lcp->options[len] = MRU;
99                 lcp->options[len + 1] = 4;
100                 memcpy(lcp->options + len + 2, &mru, sizeof(mru));
101
102                 len += 4;
103         }
104
105         if (lcp->req_options & REQ_OPTION_ACFC) {
106                 lcp->options[len] = ACFC;
107                 lcp->options[len + 1] = 2;
108
109                 len += 2;
110         }
111
112         if (lcp->req_options & REQ_OPTION_PFC) {
113                 lcp->options[len] = PFC;
114                 lcp->options[len + 1] = 2;
115
116                 len += 2;
117         }
118
119         lcp->options_len = len;
120 }
121
122 static void lcp_reset_config_options(struct lcp_data *lcp)
123 {
124         /* Using the default ACCM */
125
126         lcp_generate_config_options(lcp);
127 }
128
129 /*
130  * signal the Up event to the NCP
131  */
132 static void lcp_up(struct pppcp_data *pppcp)
133 {
134         ppp_lcp_up_notify(pppcp_get_ppp(pppcp));
135 }
136
137 /*
138  * signal the Down event to the NCP
139  */
140 static void lcp_down(struct pppcp_data *pppcp)
141 {
142         struct lcp_data *lcp = pppcp_get_data(pppcp);
143
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));
147 }
148
149 /*
150  * Indicate that the lower layer is not needed
151  * Should trigger Down event
152  */
153 static void lcp_finished(struct pppcp_data *pppcp)
154 {
155         ppp_lcp_finished_notify(pppcp_get_ppp(pppcp));
156 }
157
158 static void lcp_rca(struct pppcp_data *pppcp, const struct pppcp_packet *packet)
159 {
160         struct ppp_option_iter iter;
161
162         ppp_option_iter_init(&iter, packet);
163
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)) {
167                 case ACCM:
168                         /*
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.
173                          */
174
175                         ppp_set_recv_accm(pppcp_get_ppp(pppcp),
176                                         get_host_long(data));
177                         break;
178                 default:
179                         break;
180                 }
181         }
182 }
183
184 static void lcp_rcn_nak(struct pppcp_data *pppcp,
185                                 const struct pppcp_packet *packet)
186 {
187         struct lcp_data *lcp = pppcp_get_data(pppcp);
188         struct ppp_option_iter iter;
189
190         ppp_option_iter_init(&iter, packet);
191
192         while (ppp_option_iter_next(&iter) == TRUE) {
193                 const guint8 *data = ppp_option_iter_get_data(&iter);
194
195                 switch (ppp_option_iter_get_type(&iter)) {
196                 case MRU:
197                 {
198                         guint16 mru = get_host_short(data);
199
200                         if (mru < 2048) {
201                                 lcp->mru = get_host_short(data);
202                                 lcp->req_options |= REQ_OPTION_MRU;
203                         }
204
205                         break;
206                 }
207                 default:
208                         break;
209                 }
210         }
211
212         lcp_generate_config_options(lcp);
213         pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
214 }
215
216 static void lcp_rcn_rej(struct pppcp_data *pppcp,
217                                 const struct pppcp_packet *packet)
218 {
219
220 }
221
222 static enum rcr_result lcp_rcr(struct pppcp_data *pppcp,
223                                         const struct pppcp_packet *packet,
224                                         guint8 **new_options, guint16 *new_len)
225 {
226         GAtPPP *ppp = pppcp_get_ppp(pppcp);
227         struct ppp_option_iter iter;
228
229         ppp_option_iter_init(&iter, packet);
230
231         while (ppp_option_iter_next(&iter) == TRUE) {
232                 switch (ppp_option_iter_get_type(&iter)) {
233                 case AUTH_PROTO:
234                 {
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];
239                         guint8 *option;
240
241                         if ((proto == CHAP_PROTOCOL) && (method == MD5))
242                                 break;
243
244                         /*
245                          * try to suggest CHAP & MD5.  If we are out
246                          * of memory, just reject.
247                          */
248
249                         option = g_try_malloc0(5);
250                         if (option == NULL)
251                                 return RCR_REJECT;
252
253                         option[0] = AUTH_PROTO;
254                         option[1] = 5;
255                         put_network_short(&option[2], CHAP_PROTOCOL);
256                         option[4] = MD5;
257                         *new_options = option;
258                         *new_len = 5;
259                         return RCR_NAK;
260                 }
261                 case ACCM:
262                 case PFC:
263                 case ACFC:
264                 case MRU:
265                         break;
266
267                 case MAGIC_NUMBER:
268                 {
269                         guint32 magic =
270                                 get_host_long(ppp_option_iter_get_data(&iter));
271
272                         if (magic == 0)
273                                 return RCR_REJECT;
274
275                         break;
276                 }
277                 default:
278                         return RCR_REJECT;
279                 }
280         }
281
282         /* All options were found acceptable, apply them here and return */
283         ppp_option_iter_init(&iter, packet);
284
285         while (ppp_option_iter_next(&iter) == TRUE) {
286                 switch (ppp_option_iter_get_type(&iter)) {
287                 case ACCM:
288                         /*
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.
293                          */
294                         ppp_set_xmit_accm(ppp,
295                                 get_host_long(ppp_option_iter_get_data(&iter)));
296                         break;
297                 case AUTH_PROTO:
298                         ppp_set_auth(ppp, ppp_option_iter_get_data(&iter));
299                         break;
300                 case MRU:
301                         ppp_set_mtu(ppp, ppp_option_iter_get_data(&iter));
302                         break;
303                 case MAGIC_NUMBER:
304                         /* don't care */
305                         break;
306                 case PFC:
307                 {
308                         struct lcp_data *lcp = pppcp_get_data(pppcp);
309
310                         if (lcp->req_options & REQ_OPTION_PFC)
311                                 ppp_set_xmit_pfc(ppp, TRUE);
312
313                         break;
314                 }
315                 case ACFC:
316                 {
317                         struct lcp_data *lcp = pppcp_get_data(pppcp);
318
319                         if (lcp->req_options & REQ_OPTION_ACFC)
320                                 ppp_set_xmit_acfc(ppp, TRUE);
321
322                         break;
323                 }
324                 }
325         }
326
327         return RCR_ACCEPT;
328 }
329
330 struct pppcp_proto lcp_proto = {
331         .proto                  = LCP_PROTOCOL,
332         .name                   = "lcp",
333         .supported_codes        = LCP_SUPPORTED_CODES,
334         .this_layer_up          = lcp_up,
335         .this_layer_down        = lcp_down,
336         .this_layer_finished    = lcp_finished,
337         .rca                    = lcp_rca,
338         .rcn_nak                = lcp_rcn_nak,
339         .rcn_rej                = lcp_rcn_rej,
340         .rcr                    = lcp_rcr,
341 };
342
343 void lcp_free(struct pppcp_data *pppcp)
344 {
345         struct lcp_data *lcp = pppcp_get_data(pppcp);
346
347         g_free(lcp);
348         pppcp_free(pppcp);
349 }
350
351 struct pppcp_data *lcp_new(GAtPPP *ppp, gboolean is_server)
352 {
353         struct pppcp_data *pppcp;
354         struct lcp_data *lcp;
355
356         lcp = g_try_new0(struct lcp_data, 1);
357         if (lcp == NULL)
358                 return NULL;
359
360         pppcp = pppcp_new(ppp, &lcp_proto, is_server, 0);
361         if (pppcp == NULL) {
362                 g_free(lcp);
363                 return NULL;
364         }
365
366         pppcp_set_data(pppcp, lcp);
367
368         lcp_reset_config_options(lcp);
369         pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
370
371         return pppcp;
372 }
373
374 void lcp_set_acfc_enabled(struct pppcp_data *pppcp, gboolean enabled)
375 {
376         struct lcp_data *lcp = pppcp_get_data(pppcp);
377         guint8 old = lcp->req_options;
378
379         if (enabled == TRUE)
380                 lcp->req_options |= REQ_OPTION_ACFC;
381         else
382                 lcp->req_options &= ~REQ_OPTION_ACFC;
383
384         if (lcp->req_options == old)
385                 return;
386
387         lcp_generate_config_options(lcp);
388         pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
389 }
390
391 void lcp_set_pfc_enabled(struct pppcp_data *pppcp, gboolean enabled)
392 {
393         struct lcp_data *lcp = pppcp_get_data(pppcp);
394         guint8 old = lcp->req_options;
395
396         if (enabled == TRUE)
397                 lcp->req_options |= REQ_OPTION_PFC;
398         else
399                 lcp->req_options &= ~REQ_OPTION_PFC;
400
401         if (lcp->req_options == old)
402                 return;
403
404         lcp_generate_config_options(lcp);
405         pppcp_set_local_options(pppcp, lcp->options, lcp->options_len);
406 }